Web-i Assistance with changing button colors

Hi There,

I am trying to change the button background colors according to the relay state
On = Green
Off = Red

I would also like to change the color of the text to either color when the relay is in that state. I figure this is an OnClick function based on RelayState but I am unsure of where to place this in the code.

              function build_button(text, onclick, classes = "button", id = ""){
          return '<button onclick="'+onclick+'" classes="'+classes+'" id="'+id+'">'+text+'</button>';
        }
		function remove_superfluous_response(response){
			response = response.replace('webiControl_Callback({"webiControlRespond":"', '');
            response = response.replace(':",});', "");
			return response;
		}
        function get_first_callback(kwargs){
            if(kwargs.hasOwnProperty('callbacks') && kwargs.callbacks.length){
                return kwargs.callbacks.shift();
            }
            else{
                return false;
            }
        }
        function get_turn_on_relay_command(relay_number){
            return wrap_api([254, 48, (relay_number-1), 0]);
        }
		function turn_on_relay(relay_number, kwargs = {'callbacks': []}){
			var cmd = get_turn_on_relay_command(relay_number);
            var bank = Math.floor((relay_number-1+8)/8);
			kwargs.bank = bank;
			send_command(cmd, kwargs);
		}
        function get_turn_off_relay_command(relay_number){
            return wrap_api([254, 47, (relay_number-1), 0]);
        }
        function turn_off_relay(relay_number, kwargs = {'callbacks': []}){
			var cmd = get_turn_off_relay_command(relay_number);
            var bank = Math.floor((relay_number-1+8)/8);
            kwargs.bank = bank;
			send_command(cmd, kwargs);
		}

        function get_set_relay_timer_command(timer, hours, minutes, seconds, relay_number){
            // timer ids start at 50 for standard timers, 70 for pulse timers, timers are shared.
            timer = timer + 49;
            relay_number = relay_number - 1;
            return wrap_api([254,50, timer, hours, minutes, seconds, relay_number]);
        }
        function set_relay_timer(timer, hours, minutes, seconds, relay_number, kwargs = {'callbacks': []}){
            var cmd = get_set_bank_status_command(timer, hours, minutes, seconds, relay_number);
            send_command(cmd, kwargs);
        }
        function get_set_relay_pulse_timer_command(timer, hours, minutes, seconds, relay_number){
            // timer ids start at 50 for standard timers, 70 for pulse timers, timers are shared.
            timer = timer + 69;
            relay_number = relay_number - 1;
            return wrap_api([254,50, timer, hours, minutes, seconds, relay_number]);
        }
        function set_relay_pulse_timer(timer, hours, minutes, seconds, relay_number, kwargs = {'callbacks': []}){
            var cmd = get_set_bank_status_command(timer, hours, minutes, seconds, relay_number);
            send_command(cmd, kwargs);
        }
        function get_set_bank_status_command(relay_binary, bank){
            return wrap_api([254,140, relay_binary, bank]);
        }
        function set_relay_bank_status_command(relay_binary, bank, kwargs = {'callbacks': []}){
            var cmd = get_set_bank_status_command(relay_binary, bank);
            kwargs.bank = bank;
            send_command(cmd, kwargs);
        }
        function get_toggle_relay_command(relay_number){
            return wrap_api([254,47, (relay_number-1), 0, 1]);
        }
        function toggle_relay(relay_number, kwargs = {'callbacks': []}){
            var cmd = get_toggle_relay_command(relay_number);
            var bank = Math.floor((relay_number-1+8)/8);
            kwargs.bank = bank;
            send_command(cmd, kwargs);
        }
		function wrap_api(cmd){
			var header = 170;
			var length = cmd.length;
			var cmd_sum = cmd.reduce((a,b) => a+b, 0);
			var checksum = (header+length+cmd_sum) & 255;
			return [header, length].concat(cmd).concat(checksum);
		}
        function get_all_adc_values_10bit_command(){
            return wrap_api([254,167]);
        }
		function get_all_adc_values_10bit(kwargs = {}){
			var cmd = get_all_adc_values_10bit_command();
			send_command(cmd, kwargs);
		}

        function get_all_adc_values_8bit_command(){
            return wrap_api([254,166]);
        }
		function get_all_adc_values_8bit(kwargs = {}){
			var cmd = get_all_adc_values_8bit_command();
			send_command(cmd, kwargs);
		}

        function get_single_adc_values_8bit_command(input){
            var input_byte = 149 + input;
            return wrap_api([254,input_byte]);
        }
		function get_single_adc_values_8bit(input, kwargs = {}){
			var cmd = get_single_adc_values_8bit_command(input);
			send_command(cmd, kwargs);
		}

        function get_single_adc_values_10bit_command(input){
            var input_byte = 157 + input;
            return wrap_api([254,input_byte]);
        }
		function get_single_adc_values_10bit(input, kwargs = {}){
			var cmd = get_single_adc_values_10bit_command();
			send_command(cmd, kwargs);
		}

        function get_relay_bank_status_command(bank){
            var cmd = [254, 124, bank];
            cmd = wrap_api(cmd);
            return cmd;
        }
        function query_relay_bank_status(bank, kwargs = {'callbacks': []}){
            // callback = get_first_callback(kwargs);
            if(!kwargs.hasOwnProperty('bank')){
                kwargs.bank = bank;
            }
            var cmd = get_relay_bank_status_command(kwargs.bank);

            send_command(cmd, kwargs);
        }
		function update_adc_UI(event, kwargs = {}){
			event = remove_superfluous_response(event);
			var adc_values = event.split(',').slice(2, event.length-1);
            var items = [].slice.call(document.querySelectorAll("[data-adc-channel]"));
            items.forEach((item, i) => {
                item.querySelectorAll('.adc_value')[0].innerHTML = adc_values[i];
                var bar_div = '<div style="width: '+(adc_values[i]/255*100)+'%"></div>';
                item.querySelectorAll('.adc_bar')[0].innerHTML = bar_div;
            });
		}
        function macros_display_response(event, kwargs = {}){
            event = remove_superfluous_response(event);
            document.getElementById('default_macros_response_target').innerHTML = event;
        }
        function get_macros_ui_json(){
          return {
    				'buttons': {
    					0: {
    						'label': 'Custom Button 1',
                            'callbacks': [
                                macros_display_response.name
                            ],
    						'commands': [
    							get_turn_on_relay_command(1),
    							get_turn_off_relay_command(1),
    							get_all_adc_values_8bit_command(),
                                get_set_relay_pulse_timer_command(1, 0, 0, 5, 1),
                                get_set_relay_timer_command(2,0,0,5,2),
                                get_single_adc_values_10bit_command(1),
                                get_single_adc_values_8bit_command(1),
                                get_all_adc_values_8bit_command(),
                                get_all_adc_values_10bit_command(),
    						],
    					},
                        // timer, hours, minutes, seconds, relay_number
    					1: {
    						'label': 'Custom Button 2',
                            'callbacks': [
                                macros_display_response.name
                            ],
    						'commands': [
                                get_turn_on_relay_command(2),
    							get_turn_off_relay_command(2),
    							get_all_adc_values_8bit_command()
    						],
    					}
    				}
    			};
        }
		function build_macros_UI(){
			var macros_JSON = get_macros_ui_json();
			var macros_html_string = '<div class="macros_wrapper test">';
			for(var button in macros_JSON.buttons){
                var onclick_array = [];
				for(var command in macros_JSON.buttons[button].commands){
                    onclick_array.push(macros_JSON.buttons[button].commands[command]);
					// onclick_string += JSON.stringify(macros_JSON.buttons[button].commands[command]);
				}

                var callback_array = []
                for(var callback in macros_JSON.buttons.callbacks){

                }

                var onclick_string = 'onclick="send_mutliple_commands('+JSON.stringify(onclick_array)+', {\'callbacks\': ['+macros_JSON.buttons[button].callbacks+']})"';
				macros_html_string += '<button class="button" '+onclick_string+'>'+macros_JSON.buttons[button].label+'</button>';
			}
			macros_html_string += '</div>';
			document.getElementById('tbc_05').innerHTML += macros_html_string;
		}
        function get_standard_ui_json(){
            return {
                'number_of_relays': 4,
                'names': [
                    'MINER 1',
                    'MINER 2',
                    'MINER 3',
                    'MINER 4',
                    ],
                'buttons': {
                    'turn_on_relay': 'On',
                    'turn_off_relay': 'Off',
                    'toggle_relay': 'Toggle',
                }
            }
        }
		function build_UI(){
            var standardJSON = get_standard_ui_json();
            var ui_html = '<div class="bank_wrapper"><div class="bank_header"><span>Bank 1</span><button class="button" onclick="query_relay_bank_status(1, {\'callbacks\': [update_relay_bank_status_ui]})">Refresh</button></div>';
            if(standardJSON.hasOwnProperty('number_of_relays')){
                var i = 1;
                var bank_check = 1;
                while(i <= standardJSON.number_of_relays){
					if(standardJSON.hasOwnProperty('names') && i <= standardJSON.names.length && standardJSON.names[(i-1)] !== false){

                    var current_bank = Math.floor((i-1+8)/8);
                    if(current_bank != bank_check){
                        ui_html += '</div><div class="bank_wrapper"><div class="bank_header"><span>Bank '+current_bank+'</span><button class="button" onclick="query_relay_bank_status('+current_bank+', {\'callbacks\': [update_relay_bank_status_ui]})">Refresh</button></div>';
                    }
                    ui_html += '<div class="relay_wrapper" data-relay="'+(i-((current_bank-1)*8))+'" data-bank="'+current_bank+'">';
                    // check if names are defined. Check if there are more relays than names.
                    if(standardJSON.hasOwnProperty('names') && i <= standardJSON.names.length){
                        ui_html += '<div class="relay_label">'+standardJSON.names[(i-1)]+'</div>';
                    }
                    else{
                        ui_html += '<div class="relay_label">Relay '+i+'</div>';
                    }
                    ui_html += '<div class="relay_status">Querying</div>';
                    if(standardJSON.hasOwnProperty('buttons')) {
                        for(var button in standardJSON.buttons){
                            ui_html += '<div class="button"><button onclick="'+button+'('+i+', {\'callbacks\': [query_relay_bank_status, update_relay_bank_status_ui]})">'+standardJSON.buttons[button]+'</button></div>';
                        }
                    }
                    ui_html += '</div>';

                    var bank_check = current_bank;
			}
                    i++;
                }
            }
            i=1;
            while(i<=current_bank){
                query_relay_bank_status(i, {'callbacks': [update_relay_bank_status_ui], 'bank' : i});
                i++;
            }
			ui_html += '<button onclick="set_relay_bank_status_command(255, 0);query_relay_bank_status(1, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(2, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(3, {\'callbacks\': [update_relay_bank_status_ui]})")>Turn On All Relays</button>';
			ui_html += '<button onclick="set_relay_bank_status_command(0, 0);query_relay_bank_status(1, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(2, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(3, {\'callbacks\': [update_relay_bank_status_ui]});">Turn Off All Relays</button>';
            document.getElementById('tbc_04').innerHTML = ui_html;
		}
        function send_command(cmd, kwargs = {}) {
          var web_i_cgi;
          cmd = cmd.join(',');
          var callback = get_first_callback(kwargs);
          setTimeout(function () { web_i_cgi = new NCD_AJAX( 'webi_control.cgi', callback, kwargs); web_i_cgi.doPost(cmd);}, 300)
        }
        function send_mutliple_commands(cmd, kwargs = {}){
            var web_i_cgi;
            cmd.forEach((item, i) => {
                cmd[i] = cmd[i].join(',');
            });
            cmd = cmd.join(':');
            var callback = get_first_callback(kwargs);
            setTimeout(function () { web_i_cgi = new NCD_AJAX( 'webi_control.cgi', callback, kwargs); web_i_cgi.doPost(cmd);}, 300)
        }
        function toHexString(byteArray) {
            return Array.from(byteArray, function(byte) {
                return ('0' + (byte & 0xFF).toString(16)).slice(-2);
            }).join(' ')
        }
        function check_packet_api(packet){
            var responses = packet.split(':');
            // console.log(responses);
            responses.forEach(function(response){
                var response = response.split(',');
                console.log('received bytes: (dec)[' + response.join(', ') + '] (hex)['+toHexString(response)+']');
                var response_checksum = response[response.length-1];
                var expected_checksum = response.reduce((a,b) => parseInt(a)+parseInt(b), 0)-response[response.length-1];
                if(response[0] != 170){
                    // console.log('Response header was not 170');
                    console.log('Response header was not 170, packet may be invalid');
                    // return false;
                }
                if(response_checksum != expected_checksum){
                    console.log('Checksum: ' + String(response_checksum) + ' is incorrect. Expected checksum of: ' + String(expected_checksum));
                }
                if(response[1] != response.length-3){
                    console.log('Payload length error. Expected ' + String(response[1]) + ' bytes, received payload of ' +  String(response.length-3) + ' bytes.');
                }
            });
        }
        // function wrap_api(cmd){
		// 	header = 170;
		// 	length = cmd.length;
		// 	cmd_sum = cmd.reduce((a,b) => a+b, 0);
		// 	checksum = (header+length+cmd_sum) & 255;
		// 	return [header, length].concat(cmd).concat(checksum);
		// }
        function update_relay_bank_status_ui(event, kwargs = {}){
            if(kwargs.hasOwnProperty('bank')){
                event = remove_superfluous_response(event);
                check_packet_api(event);
                var status = event.split(',')[2];
                var bank_elements = document.querySelectorAll("[data-bank='"+kwargs.bank+"']");
                bank_elements.forEach(function(item){
                    if(status & 1<<(item.dataset.relay-1)){
                        item.getElementsByClassName('relay_status')[0].innerHTML = "On";
                    }else{
                        item.getElementsByClassName('relay_status')[0].innerHTML = "Off";
                    }
                });
            }
        }
        function check_interval_triggers(link){
            if(link.id == 'tb_6' && adc_poll == undefined){
                var adc_poll = setInterval(function(){get_all_adc_values_8bit({'callbacks': [update_adc_UI]})}, 2000);
            }
            else if(link.id != 'tb_6' && adc_poll != undefined){
                clearInterval(adc_poll);
                var adc_poll = undefined;
            }
        }
        document.addEventListener("DOMContentLoaded", function(){
            build_UI();
            build_macros_UI();
            [].slice.call(document.getElementById('nav').children).forEach(item => item.addEventListener('click', function (){ check_interval_triggers(item) }));
        });
    </script>
</head>

Hi,

Provided you haven’t reworked the callback system for updating the UI, the section you want is inside of the function “update_relay_bank_status_ui”.

This function loops through all rows of relay elements in the target bank and updates the UI based on the state of each relay.

Ok, is there an easy way to implement this? The callback system has not been reworked. I am thinking it would be added here:

I want the buttons when selected on to be green, and when selected off to be red
Also I would like the text to be green or red to show easily what is on and off.

ui_html += '<div class="relay_status">Querying</div>';
                    if(standardJSON.hasOwnProperty('buttons')) {
                        for(var button in standardJSON.buttons){
                            ui_html += '<div class="button"><button onclick="'+button+'('+i+', {\'callbacks\': [query_relay_bank_status, update_relay_bank_status_ui]})">'+standardJSON.buttons[button]+'</button></div>';
                        }

No, the section you’re looking for primarily is the “update_relay_bank_status_ui” function.

I have added // TODO comments to the code where you can add your styling changes.

The section you referenced can be used to add classes to buttons and text to make targeting sections easier. It builds the intitial HTML structure for the control and monitoring pages.

        function update_relay_bank_status_ui(event, kwargs = {}){
            if(kwargs.hasOwnProperty('bank')){
                event = remove_superfluous_response(event);
                check_packet_api(event);
                var status = event.split(',')[2];
                var bank_elements = document.querySelectorAll("[data-bank='"+kwargs.bank+"']");
                bank_elements.forEach(function(item){
                    if(status & 1<<(item.dataset.relay-1)){
                        item.getElementsByClassName('relay_status')[0].innerHTML = "On";
                        // TODO insert custom styling code for when the relay is on
                    }else{
                        item.getElementsByClassName('relay_status')[0].innerHTML = "Off";
                        // TODO insert custom styling code for when the relay is off
                    }
                });
            }
        }

Here is what I have tried - new to adding CSS with innerHTML code honestly. Your help is much appreciated! Also I have tried to reduce the number of relays showing to 5, and I am now getting they are “Querying” for everything except for relay 1.

Relay code:

 function get_standard_ui_json(){
            return {
                'number_of_relays': 5,
                'names': [
                    'MINER 1',
                    'MINER 2',
                    'MINER 3',
                    'MINER 4',
		'MINER 5',
                    ],
                'buttons': {
                    'turn_on_relay': 'On',
                    'turn_off_relay': 'Off',
                    'toggle_relay': 'Toggle',
                }
            }
        }
type or paste code here

Here is the code:

function update_relay_bank_status_ui(event, kwargs = {}){
            if(kwargs.hasOwnProperty('bank')){
                event = remove_superfluous_response(event);
                check_packet_api(event);
                var status = event.split(',')[2];
                var bank_elements = document.querySelectorAll("[data-bank='"+kwargs.bank+"']");
                bank_elements.forEach(function(item){
                    if(status & 1<<(item.dataset.relay-1)){
                        item.getElementsByClassName('relay_status')[0].innerHTML = "On"; btn.style.backgroundColor = "#0B6623"
						
					
						
                    }else{
                        item.getElementsByClassName('relay_status')[0].innerHTML = "Off"; btn.style.backgroundColor = "#F00"
                    }
                });
            }
        }

Hi there, just curious if I can get some feedback on the above - thanks

Hi,

Is your javascript console in your browser throwing any errors?

I can’t see where you are defining btn so it will probably fail after setting the first relay to On or Off.

Ok, I got the text now changing colors when I click the button - I need to get the buttons now. Where would this code be?

 function update_relay_bank_status_ui(event, kwargs = {}){
            if(kwargs.hasOwnProperty('bank')){
                event = remove_superfluous_response(event);
                check_packet_api(event);
                var status = event.split(',')[2];
                var bank_elements = document.querySelectorAll("[data-bank='"+kwargs.bank+"']");
                bank_elements.forEach(function(item){
                    if(status & 1<<(item.dataset.relay-1)){
                        item.getElementsByClassName('relay_status')[0].innerHTML = "On";
						item.getElementsByClassName('relay_status')[0].style.color="green";
						
						
                    }else{
                        item.getElementsByClassName('relay_status')[0].innerHTML = "Off";
						item.getElementsByClassName('relay_status')[0].style.color="red";
                    }
                });
            }
        }
        function check_interval_triggers(link){
            if(link.id == 'tb_6' && adc_poll == undefined){
                var adc_poll = setInterval(function(){get_all_adc_values_8bit({'callbacks': [update_adc_UI]})}, 2000);
            }
            else if(link.id != 'tb_6' && adc_poll != undefined){
                clearInterval(adc_poll);
                var adc_poll = undefined;
            }
        }
        document.addEventListener("DOMContentLoaded", function(){
            build_UI();
            build_macros_UI();
            [].slice.call(document.getElementById('nav').children).forEach(item => item.addEventListener('click', function (){ check_interval_triggers(item) }));
        });
    </script>

This code does not exist as the buttons don’t change based on state by default.

The code can be put in the same if/else statement used for changing the state text in update_relay_bank_status_ui. You’ll need to target the buttons and alter their properties.

I am assuming the “turn_on_relay” is what I am needing to call the buttons

I did try this but it is not working, would I need the onclick handle as well? This is pretty much the last item that needs to be resolved.

if(status & 1<<(item.dataset.relay-1)){
                        item.getElementsByClassName('relay_status')[0].innerHTML = "On";
						item.getElementsByClassName('relay_status')[0].style.color="green";
						
						item.getElementsByClassName('turn_on_relay')[0].style.background.Color="green";
						
                    }else{
                        item.getElementsByClassName('relay_status')[0].innerHTML = "Off";
						item.getElementsByClassName('relay_status')[0].style.color="red";
                    }

By default the buttons do not have class names. You can give them class names in the “build_UI” function if you’d like to target them by class name.

You could also use item.getElementsByTagName(‘button’)[0] and reference them by position in the DOM [0] is first, [1] second, etc.

Hi I did manage to get the buttons to change color but they are staying the initial color without changing back to grey when the other button is selected, I am thinking I will need another If else statement…how would I go about adding this inside this area? Or should I be adding it elsewhere?

Thank you

It depends on how you want it to act. The simplest solution is to target both buttons in both the if and else to set both of their colors every time the state is updated.

Thank you so much… I am trying to move the Turn on All Relays and Turn off All Relays to the top above the relays but I am not having much luck

ui_html += '<button onclick="set_relay_bank_status_command(255, 0);query_relay_bank_status(1, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(2, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(3, {\'callbacks\': [update_relay_bank_status_ui]})")>Turn On All Relays</button>';
			ui_html += '<button onclick="set_relay_bank_status_command(0, 0);query_relay_bank_status(1, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(2, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(3, {\'callbacks\': [update_relay_bank_status_ui]});">Turn Off All Relays</button>';
            document.getElementById('tbc_04').innerHTML = ui_html;
		}

This is the code I am trying to move- I would like it before the relays instead of at the end. Would you use the var ui_html and add it under the relay list?

function build_UI(){
var standardJSON = get_standard_ui_json();

		ADD CODE HERE
		
		
		var ui_html = '<div class="bank_wrapper"><div class="bank_header"><span>Bank 1</span><button class="button" onclick="query_relay_bank_status(1, {\'callbacks\': [update_relay_bank_status_ui]})">Refresh</button></div>';

The build_UI function basically just builds a string of HTML and set the content of a particular element to the created string.

To add an element before another element you can just add it to the string before the part you want to come later on the page.

If you’re wanting to add it before this line though:

var ui_html = '<div class="bank_wrapper"><div class="bank_header"><span>Bank 1</span><button class="button" onclick="query_relay_bank_status(1, {\'callbacks\': [update_relay_bank_status_ui]})">Refresh</button></div>';

you’ll notice that the ui_html variable is instantiated here. To add something before this line you will need to have the first line that adds data to ui_html instantiate the ui_html variable and have everything below that append to that string using +=

I think I understand - I want it to sit right above the relay bank title - I likely will need another class but I am hoping to at least get it to show up first.

function build_UI(){
            var standardJSON = get_standard_ui_json();
			
			ui_html += '<button onclick="set_relay_bank_status_command(255, 0);query_relay_bank_status(1, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(2, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(3, {\'callbacks\': [update_relay_bank_status_ui]})")>Turn On All Relays</button>';
			
			ui_html += '<button onclick="set_relay_bank_status_command(0, 0);query_relay_bank_status(1, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(2, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(3, {\'callbacks\': [update_relay_bank_status_ui]});">Turn Off All Relays</button>';
            document.getElementsByClassName('bank_wrapper').innerHTML = ui_html;
			
			var ui_html = '<div class="bank_wrapper"><div class="bank_header"><span>Bank 1</span><button class="button" onclick="query_relay_bank_status(1, {\'callbacks\': [update_relay_bank_status_ui]})">Refresh</button></div>';

I have not had much experience using the ui_html code before honestly so I really appreciate your help!

Still not able to get this to show up above the bank of relays.

Hi,

If this is your latest code:

ui_html += '<button onclick="set_relay_bank_status_command(255, 0);query_relay_bank_status(1, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(2, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(3, {\'callbacks\': [update_relay_bank_status_ui]})")>Turn On All Relays</button>';
			
			ui_html += '<button onclick="set_relay_bank_status_command(0, 0);query_relay_bank_status(1, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(2, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(3, {\'callbacks\': [update_relay_bank_status_ui]});">Turn Off All Relays</button>';
            document.getElementsByClassName('bank_wrapper').innerHTML = ui_html;
			
			var ui_html = '<div class="bank_wrapper"><div class=

You’ll need to instantiate the ui_html element first and change where it is currently instantiated to an append.

var ui_html = '<button onclick="set_relay_bank_status_command(255, 0);query_relay_bank_status(1, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(2, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(3, {\'callbacks\': [update_relay_bank_status_ui]})")>Turn On All Relays</button>';
			
			ui_html += '<button onclick="set_relay_bank_status_command(0, 0);query_relay_bank_status(1, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(2, {\'callbacks\': [update_relay_bank_status_ui]});query_relay_bank_status(3, {\'callbacks\': [update_relay_bank_status_ui]});">Turn Off All Relays</button>';
            document.getElementsByClassName('bank_wrapper').innerHTML = ui_html;
			
			ui_html += '<div class="bank_wrapper"><div class=