Fox Oil Sensor - Curl API ... How?

Dear all,
some weeks ago i installed a FoxRadar Sensor by Fox Insights to monitor the level of my heater oil tank. Since then i do receive the values in the FoxOil App. However, of course i also want to import them into openhab. I found some old topics and solutions at google, but they seemed to change the API since then. Now they do have a official documented API: customer-api/docs/v1 at main · foxinsights/customer-api · GitHub

But i am a beginner and dont know how to use this API. I google “openhab curl” and found the HTTP Binding. I just tried to add the information in a HTTP Binding thing, but this doesn’t seem to work …

How to setup the thing to send this command:

curl https://api.oilfox.io/customer-api/v1/login -H 'Content-Type: application/json' --data '{"password":"mySafePassword","email":"myUser@someMailProvider.com"}'

The response should be an access token which should be used for the data request:

{
  "token_type": "Bearer",
  "access_token": "eyJ0eXAiOiJKV[...]wXdfjS9g7P7XAt6GnOQ",
  "refresh_token": "eyJ0eXAiOiJKV[...]mFpd7W2RmOx0XGvEAIg"
}

The data will then be received by such a command:

curl https://api.oilfox.io/customer-api/v1/device/ON0123456789 -H 'Authorization: Bearer eyJ0eXAiOiJKV1[...]wXdfjS9g7P7XAt6GnOQ'

Is the HTTP Binding the right way to do this?
Can someone give me a hint how to configure the thing/channel/item?

Thank you!! :slight_smile:

I had the same problem about a year ago. My workaroud was using FHEM and sending the data via MQTT to openhab. The FHEM-Plugin ist working fine. The installation of fhem on the openhab server does not require a lot of resources.

In openhab it looks like this:

The installation in FHEM is simlple:

define myOilFox OilFox
attr myOilFox userattr mqttAlias:textField-long mqttDefaults:textField-long mqttDisable:both,incoming,outgoing mqttForward:all,none mqttPublish:textField-long mqttSubscribe:textField-long
attr myOilFox email ***********
attr myOilFox mqttDefaults base={"FHEM/$device"} pub:qos=0 sub:qos=2 retain=1
attr myOilFox mqttPublish oilfox_metering_fillingPercentage|oilfox_metering_liters|oilfox_daysReach|oilfox_metering_battery|oilfox_hwid|oilfox_tankVolume|oilfox_currentMeteringAt|oilfox_nextMeteringAt:topic={"$base/$name"}
attr myOilFox password *******
attr myOilFox room OilFox

Items in openhab:

Group:Number:Litres Oel

Number    oilfox_metering_fillingPercentage     "Ölstand [%.0f%%]"            (Oel)               {channel="mqtt:topic:OilFox:oilfox_metering_fillingPercentage"}
Number    oilfox_metering_liters                "Ölstand in Litern [%.0f]"                     {channel="mqtt:topic:OilFox:oilfox_metering_liters"}
DateTime  oilfox_metering_zeit              "Letzte Messung [%1$td.%1$tm.%1$ty %1$tH:%1$tM]"   {channel="mqtt:topic:OilFox:oilfox_metering_liters" [profile="timestamp-change"]}
String    oilfox_hwid                           "Geräteid"                                      {channel="mqtt:topic:OilFox:oilfox_hwid"}
DateTime  oilfox_currentMeteringAt          "Aktuelle Messung vom [%1$td.%1$tm.%1$ty %1$tH:%1$tM]"    {channel="mqtt:topic:OilFox:oilfox_currentMeteringAt"}
DateTime  oilfox_nextMeteringAt             "nächste Messung geplant am [%1$td.%1$tm.%1$ty %1$tH:%1$tM]"                        {channel="mqtt:topic:OilFox:oilfox_nextMeteringAt"}
Number    oilfox_daysReach                     "Reichweite der Füllung in Tagen"                     {channel="mqtt:topic:OilFox:oilfox_daysReach"}

Things in Openhab:

Thing mqtt:topic:OilFox  "Oilfox"  (mqtt:broker:MosquittoMqttBroker)
           {
           Channels:
           Type number : oilfox_metering_fillingPercentage    [stateTopic="FHEM/myOilFox/oilfox_metering_fillingPercentage"]
           Type number : oilfox_metering_liters               [stateTopic="FHEM/myOilFox/oilfox_metering_liters"]    
           Type number : oilfox_daysReach                     [stateTopic="FHEM/myOilFox/oilfox_daysReach"]  
           Type string : oilfox_hwid                          [stateTopic="FHEM/myOilFox/oilfox_hwid"]  
           Type string : oilfox_metering_battery              [stateTopic="FHEM/myOilFox/oilfox_metering_battery"]
           Type string : oilfox_currentMeteringAt             [stateTopic="FHEM/myOilFox/oilfox_currentMeteringAt"]
           Type string : oilfox_nextMeteringAt                [stateTopic="FHEM/myOilFox/oilfox_nextMeteringAt"]
           }

https://fhem.de/commandref.html#OilFox

1 Like

I thin the http binding is correct

Not sure about how it works with the token needing refreshing every 15 minutes. I assume that’s what the pre-emptive authentication is but that’s just a guess.

Just put the base URL in no need for curl and select get then select show advanced settings.

You will then need to use a transformation to pull out the required values from the returned JSON.

1 Like

Dear all, thank you alot for your answers!
Good hint using FHEM, however this should be the last fall back solution. I will try first using openhab tools :slight_smile:

I tried to setup the HTTP binding yesterday the following way:

UID: http:url:86eb4e3112
label: HTTP URL Thing
thingTypeUID: http:url
configuration:
  authMode: BASIC
  ignoreSSLErrors: false
  baseURL: https://api.oilfox.io/customer-api/v1/login
  password: mypassword
  delay: 0
  stateMethod: GET
  refresh: 30
  commandMethod: POST
  contentType: application/json
  timeout: 3000
  username: mymail@address.com
  bufferSize: 2048
channels:
  - id: "123"
    channelTypeUID: http:string
    label: Test
    description: ""
    configuration: {}

I am getting the following warning in the log:

2022-10-23 07:24:31.221 [WARN ] [p.internal.http.HttpResponseListener] - Requesting 'https://api.oilfox.io/customer-api/v1/login' (method='GET', content='null') failed: 405 null

I am confused about the refresh interval. Does the 30s mean openhab is requesting every 30s again and again? In the end i only want to request once a day using a rule (for example). Is this possible?
The thing was active the complete night throwing these warning all the time and today morning my FoxOil app is not working anymore… dont know if my account is blocked now :frowning:

Short update: The FoxOil is working again (dont know what the problem was … ).

Using the ssh on the openhab Raspberry pi the request is working fine:

openhabian@openhab:~ $ curl https://api.oilfox.io/customer-api/v1/login -H 'Content-Type: application/json' --data '{"password":"mypassword","email":"maymail@mail.com"}'
{"token_type":"Bearer","access_token":"eyJ0eXAiOiJKV1QiLCJhbG.......qsgWsSM30CE8gxGTVO6r7P9S9s7lw","refresh_token":"eyJ0eXAiOiJKV1QiLCJhbGc.......lUfHklkK_oMA"}

openhabian@openhab:~ $ curl https://api.oilfox.io/customer-api/v1/device/ON...63 -H 'Authorization: Bearer eyJ0eXAiO......0CE8gxGTVO6r7P9S9s7lw'
{"hwid":"ONR149170663","currentMeteringAt":"2022-10-22T12:34:01.435Z","nextMeteringAt":"2022-10-23T12:34:01.435Z","daysReach":495,"batteryLevel":"FULL","fillLevelPercent":51,"fillLevelQuantity":2909,"quantityUnit":"L"}

Using Openhab and HTTP Binding i am still receiving the same warning:

2022-10-23 11:27:24.280 [WARN ] [p.internal.http.HttpResponseListener] - Requesting 'https://api.oilfox.io/customer-api/v1/login' (method='GET', content='null') failed: 405 null

The will a daily limit on how many times you can query the API so that is more than likely why it started to work again.from looking at your config file you don’t have the header added which you have in the ssh.

I think you are right.
The API is expecting a password and an email adress.
But i dont know how to add this … in the thing configuration i can type in a username and password. Dont know if usernamen and email address is the same in this context.

Also there is --data … dont know how to add this.

curl https://api.oilfox.io/customer-api/v1/login -H 'Content-Type: application/json' --data '{"password":"mySafePassword","email":"myUser@someMailProvider.com"}'

I tried the following, but without success.

UID: http:url:86eb4e3112
label: HTTP URL Thing
thingTypeUID: http:url
configuration:
  ignoreSSLErrors: false
  headers:
    - '"password=mypassword","email=mail@mail.com"'
  stateMethod: GET
  refresh: 30
  commandMethod: POST
  timeout: 3000
  authMode: BASIC
  baseURL: https://api.oilfox.io/customer-api/v1/login
  password: mypassword
  delay: 0
  contentType: application/json
  username: mail@mail.com
  bufferSize: 2048
channels:
  - id: "123"
    channelTypeUID: http:string
    label: Test
    description: ""
    configuration: {}

But still:

2022-10-23 19:26:28.456 [WARN ] [p.internal.http.HttpResponseListener] - Requesting 'https://api.oilfox.io/customer-api/v1/login' (method='POST', content='null') failed: 400 null

Does someone have a hint?
Thank you!

You would like to send JSON formatted data. Just putting key=value into the headers does not work as far as I understand. JSON needs to be send as part of the body not as part of the header.
Have a look to HTTP binding send JSON body in PUT request (restful api)

You need to map the body.

See this post

A smarter person that me will be able to know how to do that twice. Perhaps @J-N-K will know

For my under standing of the documentation you provide.

You have first query to get your token.

So the map for the body is

{
“password”:“mySafePassword”,
email":"myUser@someMailProvider.com
}

Then extract the token from that response. This token lasts for 15 minutes.

You then have to run your query with the token extraxted in the header to get your device data.

Thank you. This sounds pretty complicated :smiley:
Do you know how to link the map to the http thing? What to do with the “–data”? How to save the token and re-use it? Dont really know how to start :confused:

This seems to do what you need but using a script.

Hi Simon

Sending HTTP body parts in the Thing configuration is really a drag. I suggest you use two dsl rule scripts instead.

In the first script you read the access token and save it as a string Item value. You have to create this Item and give it a name. For the example let’s use “Token_Item_Name”. Then create a script that reads the token. Verify that you have the Jsonpath transformation addon installed.

var body = '{"password":"mySafePassword","email":"myUser@someMailProvider.com"}';

var loginResult = HTTP.sendHttpPostRequest('https://api.oilfox.io/customer-api/v1/login', 'application/json', body);

var accessToken = transform("JSONPATH", "$.access_token", loginResult);

Token_Item_Name.postUpdate(accessToken);

So now you got the token in your Item. Make a schedule for this script so it will read the new value when the old one has expired.

In a second script read the value of your device. You also need an Item for the value. In this example we call it “Oil_Level_Item_Name”. Just replace it with the name of your choice.

var accessToken = Token_Item_Name.state;

val header = newHashMap("authorization" -> "Bearer " + accessToken);

var readResult = HTTP.sendHttpGetRequest('https://api.oilfox.io/customer-api/v1/device/ON0123456789', header);

var fillLevelPercent = transform("JSONPATH", "$.fillLevelPercent", readResult);

Oil_Level_Item_Name.postUpdate(fillLevelPercent);

And again, repeat the execution of this script with a scedule.

I hope this helps.

2 Likes

Dear gresli,
thank you alot for your great answer and for taking the time to help me!!
I tried your solution and i think it looks very promising.
However, i am stuck at one point:

var body = '{"password":"MyPassword","email":"MyMail@mail.com"}';
var loginResult = HTTP.sendHttpPostRequest('https://api.oilfox.io/customer-api/v1/login', 'application/json', body);
var accessToken = transform("JSONPATH", "$.access_token", loginResult);
var refreshToken = transform("JSONPATH", "$.refresh_token", loginResult);
FoxOil_AccessToken.postUpdate(accessToken);
FoxOil_RefreshToken.postUpdate(refreshToken);
Thread::sleep(1000)
val header = newHashMap("authorization" -> "Bearer " + accessToken);
var readResult = HTTP.sendHttpGetRequest('https://api.oilfox.io/customer-api/v1/device/ONR149170663', header);
var fillLevelPercent = transform("JSONPATH", "$.fillLevelPercent", readResult);
FoxOil_fillLevelPercent.postUpdate(fillLevelPercent);
   Type mismatch: cannot convert from HashMap<String, String> to int; line 17, column 620, length 6

To this point everything looks good. I am reading the access and refresh token into 2 different string items. I checked the format and length of the tokens comparing them to the values i get using the shell command on the RPI and they look very similar.

But there is this error with the type mismatch. Do you know how to fix this?

The access token is looking like this (i flipped some numbers):
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiI1NmRhMjE0ZC0yMDRlLTQyMmQtODJiMS0xYmU4NzYwZWFhMGUiLCJhdWOiOiJVU0VSIiwic2NvcGUiOiJDVVNUT01FUl9BUEkiLCJpc3MiOiJvaWxmb3guaW8iLCJleHAiOjE2NjY2ZzU1ODIsImp0aSI6ImU2YmFlNDM0LWRhNGEtNDUwNC04MDMyLTEwYTVlYTQ3MTsjNyIsImVtYGlsIjoic2dvdHRvcmZAZ21haWwuY29tIn0.jsXsnknSbwOcleyt_apN-5UU65C4yH3BX4azK37kAkq2k8P3qLyYuZy8q1XarhNljQhJH-Q8YiRlOvyndi7TZQ

Edit: I managed to fix it! The timeout value for the HTTP.sendHttpGetRequest was missing based on Actions | openHAB. Now its working:

var body = '{"password":"MyPassword","email":"mail@mail.com"}';

var loginResult = HTTP.sendHttpPostRequest('https://api.oilfox.io/customer-api/v1/login', 'application/json', body);

var accessToken = transform("JSONPATH", "$.access_token", loginResult);
var refreshToken = transform("JSONPATH", "$.refresh_token", loginResult);

FoxOil_AccessToken.postUpdate(accessToken);
FoxOil_RefreshToken.postUpdate(refreshToken);


Thread::sleep(1000)


val header = newHashMap("authorization" -> "Bearer " + accessToken);

var readResult = HTTP.sendHttpGetRequest('https://api.oilfox.io/customer-api/v1/device/DEVICEID', header, 1000);

var fillLevelPercent = transform("JSONPATH", "$.fillLevelPercent", readResult);

FoxOil_fillLevelPercent.postUpdate(fillLevelPercent);

Thank all of you alot for your help!

2 Likes