Haiku Sample script code?

pct88

Member
I have read through the Haiku Helper online help files "JavaScript Bridge API Revision 2.91" and "Getting Started Revision 1.02" and tested various sample interactions between the Omni panel and HH.  It would really help me pull together a more effective combination of HH and the Omni panel if I start coding from a FULL working configuration of scripts that people have up and running. 
 
I find it much easier to take working code and modify it for my purposes than to start entirely from scratch.  Is there a repository of Haiku Helper scripts available to help users get up and running?  Obviously you would want to edit out specific passwords, e-mail and IP addresses.  Working code examples would be greatly appreciated.
 
Did you see the example scripts in the JavaScript Bridge PDF? There are some samples on this forum as well. We don't currently have a central repository for scripts.
 
Yes, I read through the entire JavaScript Bridge PDF document, and saw various samples in there.  Without a "full system" sample though I made basic errors such as thinking I could build a script for HVAC control, another script for audio systems, another related to the perimeter security, etc...  I eventually discovered that these all needed to be nested together in one large script.  A sample of a working system would have made that obvious to me while individual samples scripts don't make clear how a full system goes together.  At least not to me.
 
You are right, they go together in the sense that they are all being executed in one JavaScript environment. This is good because it lets you communicate between the different parts of your script and reuse more code. You can still break it up into separate script files on your filesystem if you like and then just include the scripts.

The key to understanding how it all goes together is to understand that the event callbacks can only be implemented in your entire automation script only once. So for example, onZoneNotReady() can only exist once. You then place logic within this function that decides what to do with the event. It could pass it to another function, to a bunch of other functions or decide which function to pass it to directly or even do something directly. Its up to you how you want to structure your script. This really depends on how complex you plan to make it (ie. how much it will actually control). More complex scripts need better structure for maintainability, light scripting can get away with basic structure.
 
Its not really possible to provide a whole working system, because its completely different for everyone -- its up to you to decide what you would like to do, then you can integrate sample code into your script.
 
I am not requesting that  a working system that would meet my specific needs be provided, rather a sample of a system that works for someone that includes some well structured (and commented) complex scripts as an example to inspire us for what is possible.  Sort of the difference between an English course where you read a number of classic books to consider and incorporate the styles and such into your own writing vs. handing someone a dictionary and grammar textbook and saying "here, this is all you need to learn to write".  
 
lupinglade said:
You are right, they go together in the sense that they are all being executed in one JavaScript environment. This is good because it lets you communicate between the different parts of your script and reuse more code. You can still break it up into separate script files on your filesystem if you like and then just include the scripts.

The key to understanding how it all goes together is to understand that the event callbacks can only be implemented in your entire automation script only once. So for example, onZoneNotReady() can only exist once. You then place logic within this function that decides what to do with the event. It could pass it to another function, to a bunch of other functions or decide which function to pass it to directly or even do something directly. Its up to you how you want to structure your script. This really depends on how complex you plan to make it (ie. how much it will actually control). More complex scripts need better structure for maintainability, light scripting can get away with basic structure.
Is this correct? or should "onZoneNotReady() be there only once?
 
function onZoneNotReady(zone) {
if(zone.number == 2) {// Match zone by number
helper.sendNotification(controller, zone.bestDescription + ' Open!'); } }
 
function onZoneNotReady(zone) {
if(zone.number == 3) {// Match zone by number
helper.sendNotification(controller, zone.bestDescription + ' Open!'); } }
 
function onZoneNotReady(zone) {
if(zone.number == 8) {// Match zone by number
helper.sendNotification(controller, zone.bestDescription + ' Open!'); } }
 
function onZoneSecure(zone) {
if(zone.number == 17) {// Match zone 17 by number
helper.sendNotification(controller, zone.bestDescription + ' Someone is here!'); } }
 
There is no need for the function to be there each time, you can use the function once, but you must make sure to move the closing } to the very end.   (I didn't actually check this, but at quick glance it looks right)
 
Code:
function onZoneNotReady(zone) {
  if(zone.number == 2) {// Match zone by number
     helper.sendNotification(controller, zone.bestDescription + ' Open!');
 }  
  if(zone.number == 3) {// Match zone by number
     helper.sendNotification(controller, zone.bestDescription + ' Open!');
 } 
  if(zone.number == 8) {// Match zone by number
     helper.sendNotification(controller, zone.bestDescription + ' Open!');
 } 
  if(zone.number == 17) {// Match zone 17 by number
     helper.sendNotification(controller, zone.bestDescription + ' Someone is here!'); 
 } 
}
 
I can paste up what I have for my scripting right now, it has 2 main functions... one is to handle temperature setbacks when I arm and disarm the alarm, and the other is to read in information from my Rainforest EAGLE smart meter interface.
 
It's almost 300 lines long, so I'll have to find a way to paste it in that doesn't look like crap.
 
neillt said:
I can paste up what I have for my scripting right now, it has 2 main functions... one is to handle temperature setbacks when I arm and disarm the alarm, and the other is to read in information from my Rainforest EAGLE smart meter interface.
 
It's almost 300 lines long, so I'll have to find a way to paste it in that doesn't look like crap.
 
Awesome!  Thx
 
evanlifetv said:
There is no need for the function to be there each time, you can use the function once, but you must make sure to move the closing } to the very end.   (I didn't actually check this, but at quick glance it looks right)


Code:
function onZoneNotReady(zone) {
  if(zone.number == 2) {// Match zone by number
     helper.sendNotification(controller, zone.bestDescription + ' Open!');
 }  
  if(zone.number == 3) {// Match zone by number
     helper.sendNotification(controller, zone.bestDescription + ' Open!');
 } 
  if(zone.number == 8) {// Match zone by number
     helper.sendNotification(controller, zone.bestDescription + ' Open!');
 } 
  if(zone.number == 17) {// Match zone 17 by number
     helper.sendNotification(controller, zone.bestDescription + ' Someone is here!'); 
 } 
}
Or you could make it even prettier using a switch statement:
Code:
function onZoneNotReady(zone) {
 switch(zone.number) {
  case 2: // Match zone by number
  case 3:
  case 8:
     helper.sendNotification(controller, zone.bestDescription + ' Open!');
     break;
  
  case 17: // Match zone 17 by number
     helper.sendNotification(controller, zone.bestDescription + ' Someone is here!'); 
     break;
 } 
}
 
lupinglade said:
Or you could make it even prettier using a switch statement:
Code:
function onZoneNotReady(zone) {
 switch(zone.number) {
  case 2: // Match zone by number
  case 3:
  case 8:
     helper.sendNotification(controller, zone.bestDescription + ' Open!');
     break;
  
  case 17: // Match zone 17 by number
     helper.sendNotification(controller, zone.bestDescription + ' Someone is here!'); 
     break;
 } 
}
I'll have to try that out....
Thanks!
 
Oh Lupinglade, using the switch statement, its almost like you know something about this app or at least some sort of programming language! :)
 
Thanks for the tips btw. 
 
Here is the temp setback code I wrote.  I could clean it up with switch statements but haven't gotten around to it all.
 
Code:
function onAreaArm(area){
	switch (area.mode) {
		case 0:
			// So even though we say it's armed, mode 0 is off.  So we do nothing.
			helper.log (controller,"Armed but now in off mode");
			break;
		case 1:
			// This is the day mode, so we don't need to do anything.
			helper.log (controller,"Armed into Day Mode");
			break;
		case 2:
			// This is the night mode, also do nothing.
			helper.log (controller,"Armed into Night Mode");
			break;
		case 3:
			// Away mode.  Now we are interested.
			helper.log (controller,"Armed into Away Mode");
			// We are going to see if we have temp setback configured.  If so, we will perform the setback and then
			// store the old values into user settings somewhere.
			if (controller.unitWithName("Temp Setback").isOn == true){
				// OK, the Temp Setback flag is on, so we need to set back temps
				helper.log(controller,"Temp Setback is enabled");
				// Read the current cool setpoints
				helper.log(controller,"Current raw cool setpoint is "+controller.thermostatWithNumber(1).coolSetpoint);
				helper.log(controller,"Current descriptive cool setpoint is "+controller.thermostatWithNumber(1).coolSetpointDescription);
				currentCoolTemp = convertHAITempToF(controller.thermostatWithNumber(1).coolSetpoint);
				// Store the cool setpoint on the panel with a user setting
				helper.log(controller,"Settting the Cool Setting on the panel to "+currentCoolTemp);
				controller.userSettingWithName("Cool Setting").setValue(currentCoolTemp);
				// Read the current heat setpoints
				helper.log(controller,"Current raw heat setpoint is "+controller.thermostatWithNumber(1).heatSetpoint);
				helper.log(controller,"Current descriptive heat setpoint is "+controller.thermostatWithNumber(1).heatSetpointDescription);
				currentHeatTemp = convertHAITempToF(controller.thermostatWithNumber(1).heatSetpoint);
				// Store the heat setpoint on the panel with a user setting
				helper.log(controller,"Settting the Heat Setting on the panel to "+currentHeatTemp);
				controller.userSettingWithName("Heat Setting").setValue(currentHeatTemp);
				// Read the current thermostat mode
				helper.log(controller,"Current HVAC mode is "+controller.thermostatWithNumber(1).mode);
				// Store the mode on the panel with a user setting
				helper.log(controller,"Settting the HVAC Mode on the panel to "+controller.thermostatWithNumber(1).mode);
				controller.userSettingWithName("HVAC Mode").setValue(controller.thermostatWithNumber(1).mode);
				
				// All right... we have snagged all of the thermostat information.  Now let's perform setbacks.
				// If there is a dog at home we won't want to turn the system off entirely, just bring up the temps.
				if (controller.unitWithName("Dog in House").isOn == true){
					helper.log(controller,"Showing armed away with a dog at home");
					// Just set the cool to 80 degrees, which is the HAI native temp of 134
					helper.log(controller,"Setting thermostat cool setpoint to 80 degrees");
					controller.thermostatWithNumber(1).setCoolSetpoint(80);
					// Just set the heat to 50 degrees, which is the HAI native temp of 100
					helper.log(controller,"Setting thermostat heat setpoint to 50 degrees");
					controller.thermostatWithNumber(1).setHeatSetpoint(50);
					// Set the thermostat to automatic
					helper.log(controller,"Setting thermostat to automatic mode");
					controller.thermostatWithNumber(1).setMode(3);
					// Now set the flag so that we know we mucked with the temps
					controller.unitWithName("Temp Adjust").on();
				}
				if (controller.unitWithName("Dog in House").isOn == false) {
					// OK so there isn't a dog at home, so we can just turn off the HVAC.
					helper.log(controller,"Showing armed away and no dog at home.");
					helper.log(controller,"Turning off HVAC");
					controller.thermostatWithNumber(1).setMode(0);
					// Don't forget to set the adjusted flag
					controller.unitWithName("Temp Adjust").on();
				}	
			}
			if (controller.unitWithName("Temp Setback").isOn == false){
				// The Temp Setback flag is not on, so we won't mess with the temps
				helper.log(controller,"Temp Setback is NOT enabled.");
			}
			break;
		case 4:
			// Vacation mode.  What is this anyway?
			helper.log (controller,"Armed into Vacation Mode");
			break;
		case 5:
			// Day Instant Mode
			helper.log (controller,"Armed into Day Instant Mode");
			break;
		case 6:
			// Night delayed mode
			helper.log (controller,"Armed into Night Delayed Mode");
			break;
	}
}

function onAreaDisarm(area) {
	// OK, so now the alarm is disarmed.
	if (controller.unitWithName("Temp Adjust").isOn == true) {
		// OK, so we adjusted the temps when we armed the alarm.
		helper.log(controller,"Showing alarm disarmed, and temps were adjusted");
		// Let's pull the stored temps, restore them to the thermostat
		helper.log(controller,"Resetting cool setpoint to "+convertHAITempToF(controller.userSettingWithName("Cool Setting").value));
		controller.thermostatWithNumber(1).setCoolSetpoint(convertHAITempToF(controller.userSettingWithName("Cool Setting").value));
		helper.log(controller,"Resetting heat setpoint to "+convertHAITempToF(controller.userSettingWithName("Heat Setting").value));
		controller.thermostatWithNumber(1).setHeatSetpoint(convertHAITempToF(controller.userSettingWithName("Heat Setting").value));
		// Now set the existing operating mode
		helper.log(controller,"Resetting HVAC mode to "+controller.userSettingWithName("HVAC Mode").value);
		controller.thermostatWithNumber(1).setMode(controller.userSettingWithName("HVAC Mode").value);
		// Last, clear the flag that shows we adjusted things
		helper.log(controller,"Clearing Temp Adjust flag");
		controller.unitWithName("Temp Adjust").off();
	}
	if (controller.unitWithName("Temp Adjust").isOn == false) {
		// Alarm is disarmed, but we didn't adjust temps when we left.
		helper.log(controller,"Temps were not adjusted when originally armed");
		// clear the flag just to be sure
		controller.unitWithName("Temp Adjust").off();
	}
}


	

function convertHAITempToF(temperature) {
	// This function takes the funky HAI temperature format and turns it into something useful.
	// First thing to do is get it into degrees celsius.
	tempInC = Math.round((-40)+(temperature*.5));
	helper.log(controller,"The Convert Routine thinks that the temperature in C is "+tempInC);
	// Then convert that to Farenheit.
	tempInF = Math.round((tempInC*1.8)+32);
	helper.log(controller,"The Convert Routine thinks that the temperature in F is "+tempInF);
	// Write the result back to the funcion
	return tempInF;
}
 
Back
Top