User Tools

Site Tools


supported_hardware:json

JSON Interface

The JSON interface accepts an incoming web requests and processes them to control units or send back other data you can generate from scripts. The web request doesn’t need to include any JSON data at all. The action can be taken directly from the command line or from either GET or POST form variables as managed by your unit script. Anything from JSON data structures, simple success messages or entire web pages can be returned from the scripts in response to the request.

Open the preferences window and select “new interface” from the Interfaces tab. Give the interface a descriptive name and set the Device Type popup to “json”. This will bring up the JSON controls.

Port Number

You must select a unique high port number. Technically this can be in the range of 1024 to 65000 or so but higher numbers are better. The default is 21111 but if you run more than one JSON server this will need to be changed. Most services that you might want to hit this server will require that you pass through a port from the internet so that their cloud servers or what have you will be able to reach your system. What address you use to access the system will depend on whether or not the client device or service is out on the internet or internal to your network.

Tokens

Every request is required to have a known token as the first part of the path. You can use the same server for multiple different clients and give them separate tokens. Give each token a descriptive name for what it will be used for.

Creating JSON Units

Once you’ve setup and enabled the server you can begin to create units that can be controlled or sent messages through the server. Creating a unit is no different than the unit for any other device except that the unit address is up to you. It should be relatively short, be descriptive and have no spaces or other characters that cannot be included in a URL. For example: JamesPhoneHome or JamesPhoneIBeaconOffice are all fine. Be sure to select the correct interface that you created in the earlier step and the device type should default to “register” If you wish your unit to be able to hold numerical values then click the “dimmable” checkbox and leave the dimmable type as “simple” if the unit needs only to hold on and off values then do not check the dimmable checkbox. You should also check the “receive only” and “ignore clicks in list” checkboxes as JSON units can’t send data, they can only receive it. Please note that the unit name is distinct from the unit address. It is the address that is passed in the JSON server links. Your unit name can contain any characters or be as long as you wish.

Simple URL Control

If the service or device you wish to link to a Unit can make a regular http request then it can control the unit. Now that you have a Token and a unit address you can send it simple commands. Without any scripting a web request can turn on or off a unit and set it’s value. You can test this with a regular browser by putting these links into it, however browsers tend to pre-cache the initial hit before you’ve even pressed enter so expect some potentially odd behavior if you’re testing that way. A better way might be with curl from the command line.

http://your.address:21111/token/UnitAddress/on
http://192.168.0.50:12345/30587A61397042/JamesPhoneHome/off
http://rockon.ddns.net:5001/30587A61397042/someAnalog/623.1

The link has 5 parts. The first part is your server IP address or DNS name. This should be the form of the address that whatever client is loading the link would need to use to reach your server. The second is the port number you setup in the preferences. The first portion of the link text is a token. The second portion of the link is the unit address. Unit Addresses are not case sensitive. The last portion of the link is the command. Valid commands are “on”, “off”, or any numerical value.

Any other form elements or data, get/post or any other content in the request is ignored in the case of the simple URL control. The client will be sent a simple success message whether there is any unit by that address to actually control or not.

Getting Unit Data as JSON

As of build #919 you can now also use a link to the /token/address/data to receive automatically a JSON object containing all of the units data. This is a quick way to get the state or value of a unit without having to do any applescripting to return something from the on JSONRequest() handler documented below. The link to /data will return a simple JSON object to the requestor with the following values in it:

JSON keydata typedescription
”name”stringthe name of the unit
”address”stringthe address of the unit
”lastactivity”datea json formatted date of the last activity
”value”floatthe numerical value of the unit
”state”boolean true if value is not 0
”uniqueid”numberthe unique id of the unit in XTension. This ID will not change and can be used in place of the name in most scripting commands.
”description”stringwhatever is in the description field of the unit
”dimmable”booleantrue if the unit holds a number, false if discrete (on/off)
”blocked”booleantrue if the unit is blocked and no commands will be accepted
”devicetype”stringat the moment will always be “register”
”onlabel”stringthe string that should be displayed for value if the unit is on, or empty
”offlabel”stringthe string that should be displayed for value if the unit is off, or empty
”label”stringeither the on or off label already taking into account the current state of the unit
”receiveonly”booleantrue if the unit will not send commands

Receiving JSON Or Using Form Variables

Many services do not make separate link hits for on or off but will send you a JSON object or use form variables to send you their information. There may be much more information in the form or JSON that you wish to do something with. This example will show how to setup the “Geohopper” iOS app for geofencing and iBeacon sensing. This app sends the enter or exit information in a JSON object that is sent via POST to the JSON server.

When a unit receives the more complicated data structures they are converted into AppleScript records and passed to a special handler in the units ON script. You can check them there and perform whatever actions you wish. In order to access the unit in this manner the link is the same as the simple request up until the command. A JSON hit has no command at the end.

http://your.address:21111/token/UnitAddress/
http://192.168.0.50:12345/30587A61397042/JamesPhoneHome/
http://rockon.ddns.net:5001/30587A61397042/someAnalog/

If no command is found at the end of the link then all the data, JSON, GET or POST form elements and the header elements are packaged up and passed to the script. You must reply to this type of request or the client will get a timeout after 20 seconds and be disconnected. Even if your client doesn’t require a particular response you must respond in the script so that the connection can be closed before the timeout error.

In order to receive the data inside the ON script you need to create a handler called “JSONRequest” with 2 parameters, formData and JSONData. like so:

on JSONRequest( formData, JSONData)

end JSONRequest

The 2 data variables passed will be appleevent records with keyed value pairs that correspond to the values sent to the JSON server. Inside the formData record will be all GET and POST variables as well as the header lines. If no JSON data is sent from the server then the JSONdata will be an empty record, but you must still include it in the handler definition even if you’re not expecting any data there.

Using Form Variables

GET and POST form variables will both be placed into the formData record. If you have a request link such as:

http://your.server:port/30587A61397042/unitAddress?insideTemp=74.5&outsideTemp=39.8

you can receive that in the ON script like this:

on JSONRequest( formData, JSONData)

   try
     set myInsideTemp to insideTemp of formData
     set myOutsideTemp to outsideTemp of formData
     
     
     write log “the inside temp is “ & myInsideTemp
     write log “the outside temp is “ & myOutsideTemp
     
     send reply “success” return code 200 content type “text/plain"
     
   on error
     write log “expected variables were missing"
     
     send reply “failure” return code 400 content type “text/plain"
   end try
   
    
   
end JSONRequest

If you wish you could set different pseudo units to those values as they come in. The data doesn’t have to be numerical you could just as easily be working with strings or names or anything else.

In addition to all form variables you can also use the “URL” keyword to get the full path requested.

set theLink to URL of formData

would be filled with “30587A61397042/unitAddress”

Using JSON data

JSON data can be more complicated with embedded dictionaries and arrays which are converted to appleevent records just like the form data. It greatly helps to know something about the structure of what is communicating with you before you start writing code to read it. This example will be getting the data out of a Geohopper WebService connection. Geohopper is a geofencing and iBeacon application for iOS. Geohopper will not send a separate link for entering or exiting, but it does send a JSON object that has that information in it. Here’s an example of the JSON output from Geohopper:

{
    "sender”:”myEmail@myHost.com",
    "location”:"James office beacon",
    "event":"LocationExit",
    "time":"2015-09-01 22:21:49 +0000”
}

This JSON object is simple, only variables on the first level. To make use of this information I would create a unit on the JSON interface with an address something like “JamesOfficeBeacon”. In the Geohopper webService configuration I would enter a web link something like:

http://myHouse.ddns.net/30587A61397042/JamesOfficeBeacon/

If the WebService in Geohopper is set to use POST then the above JSON object is sent to XTension. In the ON script of the JamesOfficeBeacon you’d need a script something like this:

on JSONRequest( formData, JSONData)

  try 
    set myAction to |event| of JSONData
    
    if myAction is “LocationEnter” then
      turnon (thisUnit)
    else if myAction is “LocationExit” then
      turnoff (thisUnit)
    else if myAction is “LocationTest” then
      write log “a test event was received for “ & (thisUnit) color blue
    else
      write log “an unknown event was received: “ & myAction color red
    end if
    
  on error
    
    write log “JSON data from Geohopper did not have an event parameter.” color red
    
  end try
  
  send reply “success” return code 200 content type “text/plain"

end JSONRequest

any other scripting that you need to do in the ON script will run when you turn on thisUnit. Just make sure it is not inside the JSONRequest handler. The other interesting thing you’ll notice there are the pipe characters around the word event “|event|” this is an interesting applescript feature. Since record names are not enclosed in quotes they are like words in applescript itself. So you couldn’t get the value of anything that was already a reserved word in applescript. If there was a JSON variable named “on” or “error” or any of the other words that the language used it would generate an error when you tried to compile it. The pip characters around it like that let the compiler know that you want the literal word as a key into the record and not whatever the language thinks that word should mean. You dont need them unless you know the word is part of the applescript language or unless it’s giving you errors when trying to compile that part.

Sending the Response

A new dictionary verb has been added to send the response back to the client. You can see it at the end of the example script above.

  send reply “the page data” return code <numerical http response code, 200 for success> content type <http content type, text/html, text/plain, application/json, application/x-www-form-urlencoded> 
  
  send reply “<html><body><h1>Success!</h1></body></html>” return code 200 content type “text/html"
  
  send reply “{\“unitvalue\”:\”500\”, \“timeToEmpty\”:\”30\”, \“tankFileLevel\”:\”15\”, \“alarmStatus\”:\”clear\”}” return code 200 content type “application/json”

you can return actual HTML, simple text or even full JSON objects to the client.

Figuring out what the server is sending you

If you dont have full documentation for the service that you’re trying to get to connect to you finding the variable names and their placement in the JSON object or form variables can be quite frustrating. If you’ve got a connection and want to see the raw data and all the variables that are sent back and forth place the JSON server interface into debug mode. Select the JSON server from the interface status sub menu of the window menu and click the debug checkbox. After that all connections that are received will create an output file on your desktop with the contents of the request to make finding the correct form variable or JSON key easier. Here’s a sample of the output from the geohopper app:

2015-09-01 3:54:28 PM
begin data available( 1) with available count of 271data in buffer length is: 0
POST /04G34ZU9C35CA2/JAMESOFFICEBEACON/ HTTP/1.1
Content-Type: application/json
Connection: close
Host: myhouse.ddns.bz:21111
Content-Length: 121

NO GET parameters were found
content lenth=121 buffer size=121 all received in one event.
JSON Data: begin
{
    "sender”:”myEmail@myServer.com",
    "location":"Jamie office beacon",
    "event":"LocationTest",
    "time":"2015-09-01 19:54:28 +0000"
}

----------end
connection closed.

See Also

History

  • The JSON server for simple commands first appeared in build #846. The JSON and form variable handling was added in build #893.
  • support for the /data entry was added in build 919
supported_hardware/json.txt · Last modified: 2023/02/13 14:52 by 127.0.0.1