Use Wirelesstag sensors with OpenHAB?

I noticed i had a typo but another error

2016-01-31 14:42:08.534 [DEBUG] [.JSonPathTransformationService] - transformation resulted in '21.597572326660156’
2016-01-31 14:42:08.534 [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule ‘UnpackWirelesstagPayload’: Could not invoke method: org.openhab.model.script.actions.BusEvent.postUpdate(org.openhab.core.items.Item,java.lang.Number) on instance: null

Hi Aidan,
I was trying to implement your integration to get to the temp, humidity and Batt state of the tags, but I’m running into an issue to get the Authorization and Token setup from my taglist.
I went to : http://wirelesstag.net/eth/oauth2_apps.html
But don’t understand what I’m supposed to do there to obtain the needed codes.
Can you explain in ‘laymans’ terms what I’m supposed to fill in?
thanks.

Ps, this past week my method using lynx --dump http://www.mytaglist.com/ethLogShared.asmx/GetLatestTemperatureRawDataByUUID?uuid=8251… Stopped working. Likely they updated something on their server side and now it returns an exception:
System.ArgumentException: The UTC Offset for Utc DateTime instances must be 0.
Parameter name: offset
at System.DateTimeOffset…ctor(DateTime dateTime, TimeSpan offset)
at MyTagList.ethLogShared.GetLatestTemperatureRawDataByUUID(String uuid)

I’ve not been relying much on their direct support, but peruse the google group instead.
–Paul–

By no means an expert in this but…

Just create a new app (name not important)

https://www.mytaglist.com/oauth2/authorize.aspx?client_id=[client ID of your app]

Open this in a browser and login and grant access

Take note of the code it gives you

Use the code in your call

I’m pretty sure its as simple as that…

Hmm,
I get a 403–Forbidden: access is denied error after I grant access.

I don’t think that’s an issue per say. That’s just a redirect error and you aren’t using that. Check the URL it gives you back and see if it has an authorisation code included

Thanks Aidan!
I now understood where to find the authorisation code.
I’m working at the scripts now. I can already get them in their raw form.
It looks that the “GetTagList” only returns the data from the sensors connected to one of the tagmanagers in a group (I have 2 groups one for home and one for the office.)
Something to look into once I have some sensors posted in my openhab… (babysteps)

OK, needed to use “GetTagList2” to read all sensor data from all tagmanagers under the same account.

I have these tags integrated with OpenHAB using a shell script method as exampled above, however, I am using the API call to “GetTagForSlaveId” (as opposed to the “StopBeep” used above):

While this works, it is slow and clearly not optimal as all of the tag data can be pulled in a single query using GetTagList as @a8ree mentioned above.

@a8ree, were you able to successfully loop through the returned data using GetTagList and parse out the various data fields? If so would you mind posting what that looks like? I assume the loop happens in a rule, but I don’t understand how that’s implemented exactly.

Also, one of the returned fields is “lastComm” which is of datatype Long. I read somewhere that this value is the number of ticks since epoch…and I found some information on converting that to a Unix timestamp with some simple math, something like t = lastComm / 10000000-11644477200
(Referenced here: https://groups.google.com/forum/#!topic/wireless-sensor-tags/TjQ2PsJz6Tk)
At any rate, my attempts to convert this into something I can use in openHAB have failed. What I’m ultimately trying to do is to use the lastComm value to calculate the elapsed time since that value (i.e. Elapsed time since tag was polled). Anyone have any ideas on how to accomplish this?

Lastly, I scrubbed through the API documentation and found the definitions for eventState. Figured I could at least contribute that much.

Hi @peteraquino

I tried in vain to get a loop to work so have ended up with and inelegant solution…but it works

Items

rule UnpackWirelesstagPayload when
Item WirelesstagPayload received update then
val String payload = WirelesstagPayload.state.toString

// Sensor 0
logInfo(“wt”, transform(“JSONPATH”, “$.d[”+0+"].name", payload))
logInfo(“wt”, transform(“JSONPATH”, “$.d[”+0+"].temperature", payload))
logInfo(“wt”, transform(“JSONPATH”, “$.d[”+0+"].alive", payload))
logInfo(“wt”, transform(“JSONPATH”, “$.d[”+0+"].eventState", payload))
TagName00.postUpdate(new StringType(transform(“JSONPATH”, “$.d[”+0+"].name", payload)))
Alive00.postUpdate(new StringType(transform(“JSONPATH”, “$.d[”+0+"].alive", payload)))
Temperature00.postUpdate(new DecimalType(transform(“JSONPATH”, “$.d[”+0+"].temperature", payload)))
val String eventState00 = transform(“JSONPATH”, “$.d[”+0+"].eventState", payload)
switch eventState00 {
case “0” : EventState00.postUpdate(“Disarmed”)
case “1” : EventState00.postUpdate(“Armed”)
case “2” : EventState00.postUpdate(“Moved”)
case “3” : EventState00.postUpdate(“OPEN”) // guessing
case “4” : EventState00.postUpdate(“CLOSED”) // guessing
case “5” : EventState00.postUpdate(“DetectedMovement”)
case “6” : EventState00.postUpdate(“TimedOut”)
}

// Sensor 1
logInfo(“wt”, transform(“JSONPATH”, “$.d[”+1+"].name", payload))
logInfo(“wt”, transform(“JSONPATH”, “$.d[”+1+"].temperature", payload))
logInfo(“wt”, transform(“JSONPATH”, “$.d[”+1+"].alive", payload))
logInfo(“wt”, transform(“JSONPATH”, “$.d[”+1+"].eventState", payload))
TagName01.postUpdate(new StringType(transform(“JSONPATH”, “$.d[”+1+"].name", payload)))
Alive01.postUpdate(new StringType(transform(“JSONPATH”, “$.d[”+1+"].alive", payload)))
Temperature01.postUpdate(new DecimalType(transform(“JSONPATH”, “$.d[”+1+"].temperature", payload)))
val String eventState01 = transform(“JSONPATH”, “$.d[”+1+"].eventState", payload)
switch eventState01 {
case “0” : EventState01.postUpdate(“Disarmed”)
case “1” : EventState01.postUpdate(“Armed”)
case “2” : EventState01.postUpdate(“Moved”)
case “3” : EventState01.postUpdate(“OPEN”) // guessing
case “4” : EventState01.postUpdate(“CLOSED”) // guessing
case “5” : EventState01.postUpdate(“DetectedMovement”)
case “6” : EventState01.postUpdate(“TimedOut”)
}

etc.

and I have this defined in the items

String WirelesstagPayload { exec="<[/etc/openhab/grabit.sh:120000:REGEX((.*?))]" }

which in turn has the code

curl --silent -X POST -H “host: mytaglist.com” -H “Content-Type: application/json; charset=utf-8” -H “Authorization: bearer 6asdsdsac8-0129-4258-b220-98aa22257d21e” -H “d: “”” -H "Cac$

(Note: I have changed my auth string for security!)

I’ve not looked at the last comm value. I’m using the URL calling feature of the tags for instantly pushing events

QUESTION: Can anyone help me understand how to properly calculate/identify the number of records (tags in this case) returned in the JSON string when utilizing the exec binding/shell script/json transformations method provided above by @watou? Thanks!

At any rate, I took a stab at implementing some sort of loop. For ease of maintainability, I chose to very specifically name my openHAB items so that doesn’t really allow for dynamic value assignments. My alternative was to loop through the array and then use switch case logic to post updates to the appropriate items.

There must be a way to identify how many tags exist in the JSON array. I’d prefer set up my loop knowing my upper limit but I still don’t understand how to do that. As is, I parse the slaveID and wait until it no longer returns a valid value (it actually returns the entire JSON string) at which time I exit the loop.

rule UnpackWirelesstagPayload
when
  	Item wtPayload received update
then
 	 
 	logInfo("wt", "Wireless Tag Payload arrived...")
 	val String payload = wtPayload.state.toString
	var i = -1
	//search for no more than 999 tags (this can be modified to whatever, just be sure to adjust the ".length" in the following if statement
	while ((i=i+1) <= 999) {
		//parsing an item that doesn't exist returns the entire string
		//so a length larger than 3 characters has exceeded our max slaveID value of 999
		if (transform("JSONPATH", "$.d["+i+"].slaveId", payload).length > 3){
			return false //stop processing
			}
		
		//extract the values we care about...
		val String xSlaveId = transform("JSONPATH", "$.d["+i+"].slaveId", payload)
		val String xName = transform("JSONPATH", "$.d["+i+"].name", payload)
		val String xTemperature = transform("JSONPATH", "$.d["+i+"].temperature", payload)
		val String xHumidity = transform("JSONPATH", "$.d["+i+"].cap", payload)
		val String xBatteryRemaining = transform("JSONPATH", "$.d["+i+"].batteryRemaining", payload)
		val String xEventState = transform("JSONPATH", "$.d["+i+"].eventState", payload)
		logInfo("wt", "Wireless Tag Payload (name: " + xName + ", slaveId: " + xSlaveId + ", temp: " + xTemperature + ", cap: " + xHumidity + ", batt: "+ xBatteryRemaining + ", state: " + xEventState + ")")
		
		//Translate the eventState and store for later...
		var String xEventTranslation = ""
		switch xEventState{
			case "3": xEventTranslation = "ON"
			case "4": xEventTranslation = "OFF"
			case "5": xEventTranslation = "ON"
			case "6": xEventTranslation = "OFF"
		}
		
		//Update respective items...
		switch xSlaveId {
			case "0":{
				wtMasterBathTemp.postUpdate((new DecimalType(xTemperature)*1.8)+32) //conversion to Fahrenheit
  				wtMasterBathHumidity.postUpdate(new DecimalType(xHumidity))
  				wtMasterBathBattery.postUpdate(new DecimalType(xBatteryRemaining)*100) //conversion for display
  				wtMasterBathPIR.postUpdate(xEventTranslation)
  				}
  			case "1":{
  				wtFrontRoomTemp.postUpdate((new DecimalType(xTemperature)*1.8)+32) //conversion to Fahrenheit
  				wtFrontRoomHumidity.postUpdate(new DecimalType(xHumidity))
  				wtFrontRoomBattery.postUpdate(new DecimalType(xBatteryRemaining)*100) //conversion for display
  				wtFrontRoomPIR.postUpdate(xEventTranslation)
  			}
  			case "2":{//living room
  				wtLivingRoomTemp.postUpdate((new DecimalType(xTemperature)*1.8)+32) //conversion to Fahrenheit
  				wtLivingRoomHumidity.postUpdate(new DecimalType(xHumidity))
  				wtLivingRoomBattery.postUpdate(new DecimalType(xBatteryRemaining)*100) //conversion for display
  			}
  			// [...] etc.
		}
	}
end

And my items look like this:

String wtPayload { exec="<[/opt/openhab/configurations/scripts/getTagList.sh:300000:REGEX((.*?))]" }
Number wtMasterBathTemp "Master Bath - Temp [%.1f °F]" <thermometer> (gTemperatures, gIndoorTemperature)
Number wtMasterBathHumidity "Master Bath - Humidity [%.0f%%]" <water> (gHumidity, gIndoorHumidity)
Number wtMasterBathBattery "Master Bath - Battery Level [%d]" <battery> (gBatteries)
Switch wtMasterBathPIR "Master Bath PIR Tripped Status [%s]" <motionsensor> (US_Master)
1 Like

Peter, thanks for this it works fantastic. I am new to openHAB and not much of a programmer, so forgive the stupid question. I am trying to pull the active value from the sensor and postUpdate that to the interface but it keeps failing. I believe the fact that it is a boolean data may be the problem. I can see the value in the JSON data pull which usually displays true or false. When I try to post the data or logItem the value I get errors stating the value is null. I tried setting the value to a string using active.toString() but that did not work.

  1. I don’t see an “Active” property. Are you referring to “Alive”?
  2. Are you just trying to store the boolean value as a string (true/false) into a String item?

Assuming yes to both of those questions…

Your item might look like:

String wtMasterBathAlive "Master Bathroom Alive [%s]"

And you can just add a few lines to the rules. I’m sure you can make out where to add these:

val String xAlive = transform("JSONPATH", "$.d["+i+"].alive", payload)
...
wtMasterBathAlive.postUpdate(xAlive)

I’d probably prefer to store boolean values in a switch item (true = on, false = off) but I suppose that’s just personal preference.

Has anyone got this working with OH2?

I’m trying and get an error:

13:31:05.386 [INFO ] [rg.eclipse.smarthome.model.script.wt] - Wireless Tag Payload arrived...
13:31:05.390 [ERROR] [.script.engine.ScriptExecutionThread] - Error during the execution of rule 'UnpackWirelesstagPayload': An error occured during the script execution: The name 'transform(<XStringLiteralImpl>,<XBinaryOperationImplCustom>,<XFeatureCallImplCustom>)' cannot be resolved to an item or type.

I’m pretty new to coding so can someone give me a hint on what might be causing the error?

I am also interested to see this work with OH2, basically have been holding out buying these sensors until I know they are compatible with openHAB2. I have contacted their support to see if they can shed some light and will post back if I hear from them. Anyone out there using these tags with OH2? Thanks.

I believe my OH2 issues stem from the JSONPath transformation not playing nicely. See here: https://github.com/openhab/openhab-distro/issues/100

A small update:
@Kai Fixed the circular error in a recent snapshot so I thought i’d try this again. I now have errors stating that in my rule,. the “json string can not be null or empty”.

I’ve looked at the output from my curl script and none of the specified val String entries have null or empty values so am wondering if it’s because there are some other values in the curl script that do give null or empty responses. Either that, or I need to look more closely at my rule (copied from @peteraquino above). I’ll keep chipping away and see if I can get some progress, but might end up reverting to OH1.8 to test the rule and script there before moving it to OH2.

I believe my rule returns Null, parsing the json string, once you’ve gone beyond the actual number of tags you have. So you might try just limiting the loop to the exact number of tags.

OK, I tried this in OH1.8.3 and also in OH2 and I get the same null error. I copied the examples above and setup a test sitemap without changing any item names and the error persists. What bindings/transformations should I have for this to work? I have everything I think I need installed but might be missing something.

This is a windows install, so next step is to try it on a different OS I guess.

I used OH 1.8.2 and then 1.8.3 and you need the HTTP binding. I found the latest update includes a change permission script that is triggered at every restart. This must be corrected for the JSON polling mechanism to function. I posted a note about how I chose to fix it on the forum. You can change permissions manually, to 755, to test the scripts are being executed. Remember permissions get reset the next time openHAB is started. I log the shell script results to a log file to debug. Can you execute the CURL command from the command line and see results? If not you need to make sure your OAuth2 access token is working. Once you know the shell script is firing then check the rules are working. I had an issue in the rules with a thermostat that did not have all of the JSON properties the tags did, this caused the rules processing to fail. In your rules file you can also loginfo to see how the rules script is processing and if it fails where it is failing. Unfortunately there are several moving parts and it takes some patience to debug. Once my computer is repaired I will publish my scripts and notes I have stored on it.

  • mike

Thanks Mike, much appreciated.

I have the HTTP binding installed but haven’t set it’s config up in any special way for the wireless sensor tags… The curl command is working nicely, that much I do know.

I’ll have a look into the permissions stuff, and start trying to log the rules file. I’m not clued up enough to figure that out quickly so for anyone else interested in this, it might take me a while.