Looking for a method to do a simple http post on an event


(scott sams) #1

I have a standalone Video Surveillance system and just got my ST Hub and Home Monitoring sensors. My VS will accept an http post to trigger a camera or group of cameras. I am new to ST so I was wondering is this something I would need to look at getting the Arduino Shield and Arduino board to do? I don’t have an issue buying them but I am just not familiar with its capabilities.

Thanks!


(Stuart Buchanan) #2

there is no need for an Arduino. ST is very capable of sending a http post to a web server. Take a look at the device type below that I wrote for a community member on here which sents a http get request. For a httppost you just need to change the method. Look at my Tado device types also for a range of requests http get, post & delete requests. Should be easy enough to get you started if you have any coding experience at all.


(scott sams) #3

Awseome! Thanks. I will give it a go. This one looks a bit over me but I will mess around with it and see what I can do. I am glad to know ST can do it on its own.


(scott sams) #4

yea i don’t know who i am kidding. i would not know the first place to start on all this. i am not a programmer. its nice to know it can do what i need though.


(Tom forti) #5

@Fuzzyligic Can httpPutJson requests be done within device types or is a smart app needed?


(Stuart Buchanan) #6

@Tomforti yes they can, i used to do the same thing in my Tado Device types before i made a smartapp to encompass all the different device types


(Tom forti) #7

So what advantages is their to use a smartapp over having requests done in device type with your tados?


(Stuart Buchanan) #8

@Tomforti for example with tado i can use a single web request to get data for multiple devices at once as the data for each device is returned in JSON, when using the smartapp i can parse the response for all devices and update the attribute for each child device. if doing this solely for a device, i only parse the data for that device and discard the rest of the data as its not relevant for that device, so potentially with multiple Tado devices like me (10 Heating/Cooling Devices) i would be making 10 web requests instead of one per refresh cycle, its inefficient which is where a smartapp helps.

Smartapps will also help when doing oauth as the smartapp can manage the token refresh etc as there would only be one to connect to a cloud service for multiple devices, not one token per device.

and lastly it makes device installation easier and more user friendly as devices are then set up and configured from the Mobile app and not the IDE as is the case when using Device Types Only.


(Stuart Buchanan) #9

@ispy because you didn’t reply to my post but rather the thread i didn’t get notified of your response, do you have an example of what you want to achieve, i.e what web requests you want to send? i know its been a while :slight_smile:


(Tom forti) #10

@Fuzzyligic
So with your Tado system you were able to GET JSON for each “zone” mine is a little different. I get the JSON for the whole system. So I am not sure how I can pull apart the JSON for say temperatures and humidity and save their values for use and recall. Looking though your code it looks like this
restDevices.each { Tado -> TadoDevices << ["${Tado.type}|${Tado.id}|${Tado.name}":"${Tado.name}"] }
might save the data in the way i would need to but how would i recall the data based on the room ID? For now I am not writing a smartapp and device type. I chose to first make a device type and am specifying the “room ID” in my settings. So I need to have the httpGet request just give me the data for just the Room ID for the device. Ideas?..and thank you

Here is the JSON response that i am working with.

{
  "room_status": [
    {
      "pressure": 993.491943359375,
      "remote_time": "2017-04-10 01:51:03",
      "id": 1,
      "temp": 23.989270019531254,
      "humidity": 40.382904052734375
    },
    {
      "pressure": 994.293212890625,
      "remote_time": "2017-04-10 01:51:03",
      "id": 2,
      "temp": 22.187453613281242,
      "humidity": 45.189422607421875
    },
    {
      "pressure": 994.1083984375,
      "remote_time": "2017-04-10 01:51:03",
      "id": 3,
      "temp": 24.085795898437503,
      "humidity": 38.612884521484375
    },
    {
      "pressure": 996.075439453125,
      "remote_time": "2017-04-10 01:51:03",
      "id": 4,
      "temp": 21.56539794921874,
      "humidity": 45.136016845703125
    },
    {
      "pressure": 995.023193359375,
      "remote_time": "2017-04-10 01:51:03",
      "id": 5,
      "temp": 21.570760498046873,
      "humidity": 44.960540771484375
    },
    {
      "pressure": 994.7763671875,
      "remote_time": "2017-04-10 01:51:03",
      "id": 6,
      "temp": 23.56026611328125,
      "humidity": 38.719696044921875
    }
  ]
}

(Stuart Buchanan) #11

i do a similar thing when evaluating Tado users as i can only get a return showing all the users. check the ParseUserResponse to see how i have done this. but for your case you would need something similar to the following win your parseResponse this assumes that your room id in settings is called ventId so the result in the code will be settings.ventId

also i am assuming your device type has the following capabilities

capability "Temperature Measurement"
capability “Relative Humidity Measurement”

and the following custom attribute

attribute “pressure”, “string”

private parseResponse() {
    log.debug("Executing parseUserResponse: "+resp.data)
    log.debug("Output status: "+resp.status)
    if(resp.status == 200) {
      def restVents = resp.data.room_status
      log.debug("Executing parseUserResponse.successTrue")
      log.debug("UserId is ${userId} and userName is ${userName}")
      restVents.each { Vent -> 
      	log.debug("Vent Id is ${Vent.id}")
        if ( Vent.id == settings.ventId )
           {
                 log.debug("Vent Id matches value specified in settings evaluation Vent ID: ${Vent.id}")
                 def currentTemp = Vent.temp
                 def Temp = sendEvent(name: 'temperature', value: currentTemp, unit: getTemperatureScale())
                 def currentHumidity = Vent.humidity
                 def Humidity= sendEvent(name: 'humidity', value: currentHumidity)
                 def currentpressure = Vent.pressure
                 def Pressure = sendEvent(name: 'pressure', value: currentPressure)
           }
        }
    }
}

obviously this is only a rough section of code, you may need to format the data to only have two decimal places using something like value.round(2)

you will see that you take all the values from the request and iterate through each one until you find one where the id matches your settings and you process that section of json only, all others will be ignored in this case with the exception of where the id Matches

hope this helps you


(Tom forti) #12

Perfect I haven’t had a change to use that code that you sent me but that was exactly what I am looking for. I do have another question about the body of some of my posts. This is an example of what a post for me might be
api('fan', '{"thermostat_prefs": [{"id": 2,"fan":"auto"}]}')
Right now i have the 2 for the id in their just to test out my code. I currently have it under settings.roomid and will be using the code you sent me above to make it more practical but before I get there, my issue is how can i keep that exact format but replace the 2 with settings.roomid? I did try both JsonOutput and JsonSlurper but both didn’t work.


(Stuart Buchanan) #13

@Tomforti that does not look right the whole point of json is that they are value pairs, be that single or nested values. in your string the value name of fan does not have a value assigned to it but either way if you were using JsonOutput like i do your formatting would be something like

def jsonbody = new groovy.json.JsonOutput().toJson([fan, thermostat_prefs:[id:“2”, fan:“auto”]]) but i suspect that is not the correct format as the first fan statement does not have a value assigned.

what is probably best as that is how i work, download the free version of insomnia and get your post statement working in that its also handy for building libraries of what requests you are working with and also allows you to correctly see the full json output.

once you have a working query then post the actual json that worked directly from that program and i will be able to format correctly using jsonoutput.


(Tom forti) #14

Sorry I should have given you more code to see what’s going on. The “fan” isn’t part of the body but for the method of the Uri and http request type. I am using postman to check my requests and the format it wants is:
{“thermostat_prefs”: [{“id”: 2,“fan”:“auto”}]}
So while writing my code i just placed the 2 in as an ID to get everything to work and figured i would just come back to it once i got everything working. Now i want to switch that out for the setting.roomid but have to keep the structure. The issue i kept running into when using JsonOutput was that i couldn’t get the [ ] to stay in the structure.
If I put def jsonbody = new groovy.json.JsonOutput().toJson(["thermostat_prefs": ["id": 2,"fan":"auto"]]) I would get and output of {"thermostat_prefs":{"id":2,"fan":"auto"}} and if i included the [ ] I kept getting an error when trying to save the code.

Here is more code. It was part from your Tado and part form Nest v2.

def fanauto() {
  sendEvent(name: 'thermostatFanMode', value: auto)
  log.debug "Setting Fan to auto" 
  api('stat', '{"thermostat_prefs": [{"id": 2,"fan":"auto"}]}')
  poll()
 }
def api(method, args = [], success = {}) {
  if(!data.auth) {
    log.debug "Need to login"
    login(method, args, success)
    return
  }
  log.debug "Logged in"
  def methods = [
    'status': [uri: "https://cloud.ecovent.io/remote/v1/status", type: 'getstatus'],
    'prefs': [uri: "https://cloud.ecovent.io/remote/v1/prefs", type: 'getprefs'],
    'ignore': [uri: "https://cloud.ecovent.io/remote/v1/room_prefs", type: 'put'],
    'stat': [uri: "https://cloud.ecovent.io/remote/v1/thermostat_prefs", type: 'put'],
    'temperature': [uri: "https://cloud.ecovent.io/remote/v1/room_prefs", type: 'put']
  ]
  def request = methods.getAt(method)
  doRequest(request.uri, args, request.type, success)
 }

 // Need to be logged in before this is called. So don't call this. Call api.
def doRequest(uri, args, type, success) {
  log.debug "Calling $type : $uri : $args"
  def params = [
    uri: uri,
    requestContentType: "application/json",
    headers: ['Authorization': "token=${data.auth.cloud_authorization}"],
    body: args
  ]
    if (type == 'put') {
      httpPut(params) { resp ->
      log.debug("Put status: "+resp.status)
      }
    } else if (type == 'getstatus') {
      httpGet(params) { resp ->
        statusResponse(resp)
        }  
	 } else if (type == 'getprefs') {
      httpGet(params) { resp ->
        prefsResponse(resp)
        }
      } 
      else {
        log.debug("error")
      }
 }

(Stuart Buchanan) #15

@Tomforti if your API really is a stickler for it, Tado’s API is quite lazy if you don’t have it 100% correctly formatted as an array their API will accept it

you will need to create the array first then feed that into the jsonBuilder, this example should work i think.

def myArray=[
    id:"2", 
    fan:"auto",
]  
def myData = [ thermostat_prefs:[myArray]]
def builder = new groovy.json.JsonBuilder(myData)
def jsonStr = builder.toString()

(Tom forti) #16

That worked like a charm! Thank You


(Tom forti) #17

@Fuzzyligic So I got everything working, still need to clean up the code big time and still set up the roomid that we spoke about before. I will try and do that tomorrow and might have you eyeball my code and give me some pointers if you see them


(Stuart Buchanan) #18

Looks great, good work.

If your code is on GitHub or somewhere I will take a look. If you want I will see if I can push it into a smartapp for you as well as since you have done all the hard work doing that will be pretty quick


(Tom forti) #19

@Fuzzyligic feel I should prob check with Ecovent first before publishing. Their API isn’t open yet, I just used MITMProxy to grab all the API requests and wrote my app based on that. I mean it’s crazy that they haven’t made any intergration with Alexa, ST, Wink or IFTTT and it was the only device in my house not intergrated with ST


(Stuart Buchanan) #20

@Tomforti if they are anything like Tado who also do not have a published API then they really will not care or acknowledge as any reference to do so implies support for the API.

I approached Tado to see if they wanted to take the Tado integration off me and have it as an official integration, and they just ignored me…let me know how you get on with them.