[WITHDRAWN] Foobot Integration


I created a simple device type for the excellent Airboxlab Foobot (previously known as Alima).

This is a pretty basic regurgitation of the Foobot API. Please use Pollster or another polling app to keep it up to date!



make sure you don’t have weird characters in your endpoint e.g space

name: "foobot.io",
namespace: "copy-ninja",
author: "Jason Mok",
description: "foobot.io",
category: "",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")

preferences { page(name: "prefLogIn", title: "foobot.io")   }
def installed() { initialize() }
def updated() { initialize() }
def initialize() {
    def apiParams = [ uri: "https://api.foobot.io", 
                      path: "/v2/user/" + settings.username + "/login/" , 
                      headers: [Authorization : getApiAuth()],
                      contentType: "application/json; charset=utf-8", 
                      requestContentType: "application/json; charset=utf-8"]
    try {
        httpGet(apiParams) { log.debug it.data  }
    } catch (Error e) { log.debug "API Error: $e" } 
def prefLogIn() {
def showUninstall = username != null && password != null 
    return dynamicPage(name: "prefLogIn", title: "foobot.io", uninstall:showUninstall, install: true) {
        section("Login Credentials"){
                input("username", "text", title: "Username")
                input("password", "password", title: "Password")
def getApiAuth() {
    def basicAuth = settings.username + ":" + settings.password
    return "Basic " + basicAuth.encodeAsBase64()

Thanks @copyninja – this is for a SmartApp though right? Can you confirm this would work on a device too? Or should I focus on making the App control the device like you did for RainMachine?


httpGet() works the same way on Device Types too.

Hello, I’m inouk from foobot. If you need any help from our side let me know!

1 Like

Hi inouk – your device is great. I’m sure to have more questions soon

1 Like

@copyninja or @inouk

I am getting a ParseException when hitting the first stage of the auth process. I’ve seen this before when groovy is expecting different headers than what it expects. I pretty much implemented Jason’s code as is.

f58e3709-0501-4870-8ce2-9e9380913bab 2:38:59 PM: error error: groovyx.net.http.ResponseParseException: OK

Any ideas?

@inouk, if you can provide me with a dummy username and password, I would be able to help

So, here’s the problem. SmartThings will automatically parse the content to JSON format when the response is a JSON.
In foobot.io’s header response, it says that it’s a JSON, except that it is a not formatted as a proper JSON in the body.

I have tried to pass request in other format, but foobot.io doesn’t accept any other format other than JSON.
This is something that needs to be fixed on foobot.io’s side.


Accept: */*
Authorization: Basic <removed>
Connection: close
Host: api.foobot.io
Singularityheader: notxdetect=true


Content-Type: application/json;charset=UTF-8
Date: Mon, 05 Oct 2015 21:17:22 GMT
Server: nginx/1.9.5
X-Auth-Token: <removed>


Thanks @copyninja ! This is what I suspected. Hopefully, @inouk can accommodate. Simple changing of the header from application/json to application/text would fix this I believe, but may cause issues with existing applications. Alternatively, maybe they can whip together a different endpoint.

Thanks for everyone who helped out. I have the device up and live:


Hello sorry for getting back late, I read it is now working! Great news!

Though in JSON both true false and “true” false" are valid see: http://www.freeformatter.com/json-validator.html So it was not a bad design of our output that cause the error.

Hey @inouk - Thanks! The ST parser has its own quirks too :slight_smile:

It looks like I was actually able to bypass the whole handshake and just use the Auth Basic. So we’re good!


FYI – I have a foobot, too, but have stopped using it. It was always saying my air quality is fine. Also, my network saw it as a device with what seemed to be a Chinese chipset (products with Chinese software/firmware make me worry about Chinese hackers or government hijacking my LAN and PC’s).

Hi Kristopher,

Thank you so much for this!

I’m a bit noob at this. I followed the instructions, pasted the groovy code. There are a couple things I don’t really understand.

  1. Do I change the top of the code where there is the username and password and such? or is that part of the code?

  2. When I edit the device, it asks for a Device Network ID. Is that the same as the IP address? or is this something else?

Right now, looks like this :(, But at least there is something!

Against, super props! First time adding something like this manually. Still learning all the chops.

Hi there - same issue here - I cant seem to get any data…I think its to do with the serial number - where did you find this?

To find the hostname, you have to find the device on your network. For example, on my Asus RT-AC66 router, if I click on clients I can see all the host names that have an IP address.

Find the one with a 15 digit numerical hostname. Take that, and add “0” to the end of it. That is your serial number :slight_smile:


Thanks @Kristopher - just seen this and got it working - however it only displays the particulate matter readings and nothing else … How do I get all the other readings?

Hmm. That is certainly new behavior. Under Live Logging, can you select the Foobot and then hit refresh from the mobile app on the Foobot device. Then paste the “resp data” line. It should look something like this:

59fb0542-c322-481d-bfd2-ef09aa64cc5e  9:54:59 AM: debug resp data: [sensors:[time, pm, tmp, hum, co2, voc, allpollu], minimums:[:], thresholds:[:], datapoints:[[1452438303, 18.187, 23.226, 34.652374, 560.0, 155.0, 22.472713], [1452438611, 21.587002, 23.201, 34.79694, 572.0, 159.0, 26.444145], [1452438920, 13.937, 23.14, 34.637157, 556.0, 154.0, 18.079857], [1452439227, 17.337002, 23.039999, 34.123993, 512.0, 142.0, 19.765574], [1452439538, 13.087002, 22.931, 34.388607, 516.0, 143.0, 15.65843], [1452439846, 11.387001, 22.899, 35.095367, 565.0, 157.0, 15.958429], [1452440155, 14.787003, 22.977999, 35.16554, 561.0, 156.0, 19.215572], [1452440463, 32.637005, 23.086, 34.913605, 543.0, 151.0, 34.16929], [1452440775, 15.637001, 23.171, 34.884865, 538.0, 149.0, 19.065573], [1452441083, 11.387001, 23.157999, 34.875565, 540.0, 150.0, 14.958429]], sCompatibility:foobot, weights:[:], start:1452438303, maximums:[:], userThresholds:[:], rawValues:[], uuid:2501576570401580, units:[s, ugm3, C, pc, ppm, ppb, %], end:1452441083]

Here are a few things from the logs - including an error:

5449278a-488f-418f-87d6-b80254a266d3  5:47:45 PM: debug success
5449278a-488f-418f-87d6-b80254a266d3  5:47:45 PM: error error: groovy.lang.MissingPropertyException: No such property: tmp for class: java.lang.Integer
5449278a-488f-418f-87d6-b80254a266d3  5:47:45 PM: debug tmp: 23.44
5449278a-488f-418f-87d6-b80254a266d3  5:47:45 PM: debug pm: 7.950001
5449278a-488f-418f-87d6-b80254a266d3  5:47:45 PM: debug resp data: [sensors:[time, pm, tmp, hum, co2, voc, allpollu], minimums:[:], thresholds:[:], datapoints:[[1452445511, 7.1000023, 23.352999, 33.81626, 502.0, 139.0, 9.100002], [1452445801, 7.950001, 23.314, 34.04875, 494.0, 137.0, 9.664287], [1452446089, 7.950001, 23.329, 34.85781, 540.0, 150.0, 11.521429], [1452446378, 8.800003, 23.369999, 35.505394, 571.0, 158.0, 13.514289], [1452446666, 8.800003, 23.413, 35.846096, 600.0, 166.0, 14.657146], [1452446956, 7.950001, 23.44, 36.061676, 629.0, 175.0, 15.092857], [1452447244, 7.950001, 23.431, 36.192715, 656.0, 182.0, 16.092857], [1452447534, 7.950001, 23.448, 36.269646, 683.0, 189.0, 17.092857], [1452447822, 7.950001, 23.44, 36.440422, 706.0, 196.0, 18.092857]], sCompatibility:foobot, weights:[:], start:1452445511, maximums:[:], userThresholds:[:], rawValues:[], uuid:24015765575014E0, units:[s, ugm3, C, pc, ppm, ppb, %], end:1452447822]

Hopefully this helps