Niko Home Control


(fcela) #1

Hi there,

there is nikobus binding already available for old Nikobus protocol.
I would like to ask to advise creating new Niko Home Control binding TCP/IP protcol based.
I've found simple send command example (http://electronics.stackexchange.com/questions/103449/controlling-niko-home-control) using adruino assigned to simple API call.
Could somebody with adruino knowledge help to create niko home control bindings?
Thanks.


(Rich Koshak) #2

Check the wiki.


(fcela) #3

Could we use basic TCP/IP bindings as well?


(Rich Koshak) #4

There is a TCP binding but I've not used it. But you will be on your own implementing the protocol and messaging. If the current binding doesn't work this one should.


(Mark Herwege) #6

one get this working?

I have tried the TCP binding and can switch on/off lights. I used mappings to create the correct JSON strings. I am running into a few issues though:

I can't interpret the status feedback from NHC. The consequence is the state of switches may be out of sync if I also use NHC switches to turn lights on/off.

The NHC IP interface has a dynamic IP that changes regularly. I cannot assign a fixed IP through my router. Therefore I need to change the IP regularly in the configuration. Using wireshark and the NHC Android client I noticed their is a discovery using some UDP packets to figure out the IP and then some TCP packets to get the initial state.

As I don't have state feedback, I cannot implement dimmers.

All of this leads me to the conclusion this does need a new binding. Also because of the discovery mechanism, I think OpenHAB 2 would be a benefit. I looked at the way to decelop a binding, but I am not a Java programmer and won't have the time to finish it if I get into it. I did try to get in, but am fighting with too many things to learn.

Are there any other experiences out there?


(Rich Koshak) #7

What specifically is the problem with interpreting the status messages? Can't figure out how to transform it to ON/OFF, not receiving it at all?

Can you set up DNS that can keep up? In any case it does seem to point to needing a new binding, or at least updates to the existing binding.

Any new binding no matter whether it has discovery or not should be written against OH 2.


(Mark Herwege) #8

Rich,

Thanks for the guidance.

Here are some examples of my setup.

items:

Switch Licht_Garage "Garage" (Beneden_Garage, Lichten) {tcp=">[ON:192.168.0.122:8000:'MAP(4.map)'], >[OFF:192.168.0.122:8000:'MAP(4.map)']"}

4.map file:

ON={"cmd":"executeactions","id":4,"value1":100}
OFF={"cmd":"executeactions","id":4,"value1":0}
undefined=unknown

If the command is properly understood, NHC will respond with:

{"cmd":"executeactions", "data":{"error":0}}

For any state change, NHC will send:

{"event":"listactions","data":[{"id":4,"value1":100}]}

I don't know how to handle this.

Note that for a dimmer the value will be between 0 and 100. So the mapping file does not work.

I am not able to configure the proper mapping of the event back to the switch in OpenHab.
Also, note that I need a mapping file for each switch, witch is a lot. And I do not know how to use mapping files for dimmers.

Instead of using mapping files, I tried putting the JSON string directly in the TCP item command. I couldn't get it working because the brackets and quotes did not get trough properly.

As for the DNS problem, the DNS refresh would probably not be a problem if I had OpenHab running all the time. At the moment, there is not enough traffic to the NHC IP interface, so the lease expires.

Note that this Niko Home Control request should not be confused with Nikobus. There is a binding for Nikobus, but it is a very different animal, very different hardware.

Any suggestions?


(Rich Koshak) #9

You should be able to add an incoming (i.e. <[]) binding part and a REGEX transformation is all else fails to bring out the right data. For example the following regex should get your dimmer value.

REGEX(.*(\"value1\"\:[\d]+)\}.*)

You can also create a JavaScript transform which should be able to receive and parse the JSON before the rest of the engine gets a chance to muck with the curly brackets. If you search the forum for javascript you should see several examples of how to use the javascript transform.


(Wim) #10

I understood, we have to sent some commands to initiate the connection with NHC.
e.g. {"cmd": "startevents"} and {"cmd": "listactions"}

How are you handling this with the TCP binding?
By putting a "tcp:preamble" in openhab.cfg?

Regards
Wim


(Mark Herwege) #11

@rlkoshak Thanks for your answer. I will need to experiment a bit more. I was not aware of all transformation capabilities beyond simple map and scale. I don't know when I will find the time though.
@wim19 I didn't get to this yet. I am experimenting on a windows PC. To figure out the protocol I was running an Android emulator on the same PC. So the NHC Android client already posted these initial commands for me from the same IP. These commands are important though.
I would need to interpret all feedback from the initial listevents commands on startup of the server as this contains the full state for all switches and dimmers. But, as said, I am not there yet and don't have much time to spend on it.


(Wesley Stroop) #12

hi do you have any update on this please? If you have a solution for the dimmer i can implement it also.


(Mark Herwege) #13

Some update to this.
To start the NHC service I use a rule connected to a string item to trigger the initial commands and be able to get responses:

rule "Initialize NHC"
when
System started
then
sendCommand(NHC_Start, "{\"cmd\":\"startevents\"}")
sendCommand(NHC_Start, "{\"cmd\":\"listactions\"}")
end

In the items file I have the following for this:

/* My NHC startup item */
String NHC_Start {tcp=">[192.168.0.121:8000:'REGEX((.*))']"}

Next, for each switch or dimmer, I have a line in the items file, connected to the action in the Niko Home Control system. Here is an example:

Switch Licht_Garage "Garage" {tcp=">[192.168.0.121:8000:'JS(4.js)']"}

I then have a javascript transformation file for each of the switches or dimmers. I numbered them. Here is the full script:

(function(input_value) {

// This function maps all OpenHab switches and dimmers to Niko Home Control switches or dimmers
//	for use with the TCP/UDP binding.
// This mapping file has to exist for each switch or dimmer. The constants at the top of this file
//	need to be adjusted accordingly.

// constant to indentify Niko Home Control switch or dimmer
var item_id = 4;
// constant to identify if this is a switch or dimmer
var item_type = "switch";
// var item_type = "dimmer";

var result = "unknown";
var json_arr, i, response;

if (input_value == "ON") {
	// This is a switch to be turned on
	result = "{\"cmd\":\"executeactions\",\"id\":" + item_id + ",\"value1\":100}";
} else if (input_value == "OFF") {
	// This is a switch to be turned off
	result = "{\"cmd\":\"executeactions\",\"id\":" + item_id + ",\"value1\":0}";
} else if (/^1?[0-9]{,2}$/.test(input_value)) {
	// This is a dimmer to be set to a value between 0 and 100
	result = "{\"cmd\":\"executeactions\",\"id\":" + item_id + ",\"value1\":" + input_value + "}";
} else {
	// Here is the feedback from Niko Home Control
	// There can be multiple feedback, therefore split in multiple JSON strings
	//	and only interpret the one matching this item.
	//	If this is a switch, it should be ON or OFF.
	//	For a dimmer this should give the value between 0 and 100.
	json_arr = input_value.split("\n");
	i = 0;
	do {
		response = JSON.parse(json_arr[i]);
		try {
			if (response.event == "listactions") {
				if (response.data[0].id == item_id){
					result = response.data[0].value1;
				}
			} else if (response.cmd == "executeactions") {
				if (response.data.error == 0) {
					// command got executed well
				}
			};
		} catch (e) {
			// no match for JSON
		};
		i += 1;
	} while ((result == "unknown") && (i < json_arr.length));
	// For switches we only have ON or OFF
	if (item_type == "switch") {
		if (result == 0) {
			result = "OFF";
		} else {
			result = "ON";
		}
	}
};
return result;

})(input)

Here are my current issues with the approach:
1. While I was able to create one script that works with all switches and dimmers, I still need to duplicate them and set 2 constants at the beginning of the script. Unfortunately, I cannot pass extra variable to the transform script. That would vastly simplify my approach. I end up with multipe tens of copies to be maintained.
2. I still see a lot of errors in the TCP binding log interpreting the feedback JSON. I have not figured out why yet. It complains about the JSON string. It could be something that could be resolved in the script logic.
3. The IP address of my IP Gateway gets a DHCP address. I don't have a way to fix it in the gateway and in my router (issue with the provider home gateway, Telenet). I expected this address to be fairly static as long as it gets used, but that does not seem to be the case. It changed even while I was testing. So while you may make this work for you if you router can assign a fixed IP to the NHC IP Gateway MAC address, it does not work for me.

All of this makes me think this would need a proper binding that also includes the discovery part on the MAC address as to get the proper IP. Unfortunately, I am not fluent in Java yet. I just learned myself a bit of Javascript to get to the result you see here, but that's about it.

All inputs are more than welcome.


(Denethor) #14

Hi @Mherwege, have you advanced at all on your NHC binding ? I'm in the process of installing the NHC system, and will start using it in 8 weeks. My scripting skills are rusty, but i'm happy to offer any support in getting the binding to work.


(Mark Herwege) #15

I have refined the scripts above to the extend that I can switch lights on and off and use dimmers. It also captures switching and dimming from outside openHAB. It still isn't polished though and I cannot guarantee it will work all the time. The way it is done also means a heavy load of traffic going to each item of which most gets discarded. It probably can be done cleaner through rules with reading from and updating one item (the NHC bridge) and the real items as virtual items that get updated on NHC feedback.
Due to other priorities I have not worked on this the last few weeks. I also do not have this in a live environment. I don't expect to be doing much on it before September.


(Wim) #16

Hi @Mherwege

You seem to have made nice progress with NHC.
Can you please share the NHC sections of your rules/items/scripts and openhab.cfg?

Thanks
Wim


(Mark Herwege) #17

@wim19 @Denethor Here is what I currently have.

In the openhab.cfg file I have the following for the TCP/UDP binding.

########################### TCP - UDP Binding

# tcp:port=25001
# tcp:reconnectcron=0 0 0 * * ?
# tcp:retryinterval=5
# tcp:queue=true

tcp:buffersize=1024
tcp:itemsharedconnections=true
tcp:bindingsharedconnections=true
tcp:directionssharedconnections=true
tcp:addressmask=false

# tcp:preamble=
# tcp:postamble=\r\n

tcp:blocking=true

# tcp:timeout=3000

tcp:updatewithresponse=true
tcp:refreshinterval=250

# tcp:selecttimeout=1000/* My NHC startup item */

# tcp:charset=ASCII

In the items file I have a generic NHC start item and one item per switch/dimmer:

/* NHC Start */
String NHC_Start				{tcp=">[192.168.0.121:8000:'REGEX((.*))']"}
/* Lights NHC */
Switch Licht_Garage			"Garage"				(gBeneden_Garage, gLichten)			{tcp=">[192.168.0.121:8000:'JS(4.js)']"}
Dimmer Licht_Eetkamer		 	"Eetkamer [%d %%]" 	<slider>	(gBeneden_Eetkamer, gLichten)			{tcp=">[192.168.0.121:8000:'JS(29.js)']"}

NHC_Start is triggered with one simple rule:

import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
/**
 * The following rules help initializing the items with some helpful states.
 */
rule "Initialize NHC"
when
	System started
then
	sendCommand(NHC_Start, "{\"cmd\":\"startevents\"}")
	sendCommand(NHC_Start, "{\"cmd\":\"listactions\"}")
end

As all items are on the same TCP connection, they should each interpret the JSON feedback string and set the initial state. For this to work, I created a JavaScript transform:

(function(input_value) {

	// This function maps all OpenHab switches and dimmers to Niko Home Control switches or dimmers
	//	for use with the TCP/UDP binding.
	// This mapping file has to exist for each switch or dimmer. The constants at the top of this file
	//	need to be adjusted accordingly.
	
	// constant to indentify Niko Home Control switch or dimmer
	var item_id = x;
	// constant to identify if this is a switch or dimmer, valid values are "switch" or "dimmer"
	var item_type = x;
	
	var result = "unknown";
	var json_arr, i, response;
	
	if (input_value == "ON") {
		// This is a switch to be turned on
		result = "{\"cmd\":\"executeactions\",\"id\":" + item_id + ",\"value1\":100}";
	} else if (input_value == "OFF") {
		// This is a switch to be turned off
		result = "{\"cmd\":\"executeactions\",\"id\":" + item_id + ",\"value1\":0}";
	} else if (/^[0-9]*$/.test(input_value)) {
		// This is a dimmer to be set to a value between 0 and 100
		result = "{\"cmd\":\"executeactions\",\"id\":" + item_id + ",\"value1\":" + input_value + ",\"value2\":0}";
	} else {
		// Here is the feedback from Niko Home Control
		// There can be multiple feedback, therefore split in multiple JSON strings
		//	and only interpret the one matching this item.
		//	If this is a switch, it should be ON or OFF.
		//	For a dimmer this should give the value between 0 and 100.
		json_arr = input_value.split("\n");
		json_arr_length = json_arr.length;
		if (json_arr[json_arr_length - 1] == "") { json_arr_length--; };
		i = 0;
		do {
			print("JSON " + i + ": " + json_arr[i]);
			response = JSON.parse(json_arr[i]);
			try {
				if (response.event == "listactions") {
					if (response.data[0].id == item_id){
						result = response.data[0].value1;
					};
					if (item_type == "switch") {
						if (result == 0) {
							result = "OFF";
						} else {
							result = "ON";
						}
					};
					print("State update: " + item_type + " " + item_id + " result " + result);
				} else if (response.cmd == "executeactions") {
					if (response.data.error == 0) {
						// command got executed well
						print("Success: " + item_type + " " + item_id);
					} else {
						// error executing command
						print("Error " + response.data.error + ": " + item_type + " " + item_id);
					};
				} else if (response.cmd == "listactions") {
					// this gets parsed at initialization in response the the cmd:listactions request
					for (var key in response.data) {
						if (response.data[key].id == item_id) {
							result = response.data[key].value1;
							if (item_type == "switch") {
								if (result == 0) {
									result = "OFF";
								} else {
									result = "ON";
								}
							};
							print("State initialized: " + item_type + " " + item_id + " " + result);
						};
					};

				};
			} catch (e) {
				// no match for JSON
				print("JSON not interpreted");
			};
			i++;
		} while ((result == "unknown") && (i < json_arr_length));
	};
	return result;
	
})(input)

There are 2 parameters in the script above (item_id and item_type). One copy of this script should exist in the transform folder for each switch or dimmer as I don't know a way to pass parameters from the items file to a transform script. The name for the script is the number of switch or dimmer (=item_id) and is what you see in the call to the script in the item file. Replace the x for the item_id and item_type with the appropriate values (number and switch/dimmer).
I have automated the process of creating the multiple transform script copies using a simple awk script and batch file. That allows me to keep one master copy (the version above) and auto-generate all when I do updates. Here is the awk script and a sample batch file for a switch and a dimmer. The batch file then contains a line for each switch/dimmer.

Awk script (create_NHC_js.awk):

# replace constants with their value
/item_id = x/		{printf "\tvar item_id = %i;\n", item_id}
/item_type = x/		{printf "\tvar item_type = \"%s\";\n", item_type}

# default
! /item_.* = x/		{print $0}

Windows batch file:

gawk -v item_id=4 -v item_type="switch" -f create_NHC_js.awk NHC.js > 4.js
gawk -v item_id=29 -v item_type="dimmer" -f create_NHC_js.awk NHC.js > 29.js

This is all I have at the moment.

I believe this can be improved a lot. First, without creating a binding yet, it would probably be better to only have one item directly linked to the NHC gateway and have the switches and dimmers as virtual (string) items. When these change, a rule should than update the one linked item and the other way around. That would avoid all these items trying to interpret the same JSON and filter out the relevant parts for the item. I think my approach will lead to problems when there are a larger number of switches and dimmers. Especially dimmers will cause problems as these generate multiple updates.
Secondly, the IP address is fixed in the items file. I noticed in my install this IP address may change. I don't have the possibility through my router to fix the IP address for the NHC gateway. Using wireshark, I noticed there is some kind of discovery for the IP going on at start (using the Android app on an Android emulator on Windows), using UDP packets. Getting this is probably something for which a separate binding would be better suited. As the feedback from NHC describes the full install, it would actually allow discovery in openHAB 2. Someone with more Java skills than I have would need to tackle that though.
A 3rd future (I know I am dreaming now) would be to not only use switches and dimmers (and all other elements addressed by the NHC app), but also the elements touched by the NHC configuration app. E.g. I defined a presence simulation in NHC. But as I don't have a twilight switch in my NHC install, this presence simulation is set up with fixed times of the day. I would like to be able to overwrite them from NHC with values from the astro binding. I prefer this above defining the presence simulation in rules in openHAB as I see this as more robust.

That's the story. All input welcome. I don't have much time to spend on this though. Good luck with your configs.


(fcela) #18

Hi Mherwege,
I would like to ask how to obtain specific id for the item.
Could you check your *.nhcp configuration file (for Niko Home Control Program) if it corresponds with your specific item id?
The NHC configuration file is just .zip file, you will find config.xml file inside.
If so, we could make xsl script to map specific NHC items to OpenaHab items.

I have a huge NHC modules configuration and would like to avoid testing ids step by step.

Thanks for your reply.


(Mark Herwege) #19

@fcela It is contained in the file as ipInterfaceObjectId for each action which is defined as being available on the IP interface.
I got the ID's from the feedback on the listactions cmd you have to trigger when starting the connection (see my NHC_Start item). The feedback is then in the console window in a JSON string. It contains ID and name. I copied them over by hand, but it should be possible to get this automated, interpreting the JSON rather than using the xml.


(Mark Herwege) #20

@fcela @wim19 @Denethor @WesleyStroop I finally found some time to get a bit deeper in binding development and created a binding for The Niko Home Control system for OH2. There is no more need for the TCP binding and a complex set of rules and transformations.
In my environment, I am able go correctly auto-discover the IP interface, create an OH bridge for it and cosequently auto-discover all switch and dimmer actions in the Niko Home Control system. All these can now be triggered from OH. Actions triggered in the NHC system itself are also correctly reflected in OH.
I did not do anything with energy monitoring or thermostats. Also not all action types are covered. I only have dimmer and switch actions in my own system.
I created a pull request for it. The binding jar can be found here. Documention is here.
Feel free to test and provide feedback.


(fcela) #21

Hi Mark,

i am keen on testing the NHC binding.
Please let me know how to join you.
Thank you very much.
BR.
Marek.