OilPal / Watchman Ultrasonic Oil Tank level reading for Home Assistant

That looks good , do you correlate the two , oil level and price via some automation to alert that now is time to order or just eyeball them and order when looks good.

I’m just eyeballing it at the moment.

Still doing some testing. I’d be interested in converting what I have into an integration that could be easier to install/setup from the GUI.

If anyone has any suggestions on docs/how tos/youtube videos on where to start with that, that would be great.

Hi @c0rnflake. Many thanks for sharing your code - bringing my OilPal data into HA was always a goal of mine but I hadn’t a clue how to do it until your post!

So I’ve got the IP address of my OilPal modem and can connect to it via a browser no problem. My tank is rectangular and I also have the dimensions (l x w x h) - I also have the volume (1040 litres) as it’s printed on a label on the tank!

A few questions:

  • After 24 hours, I am getting a state of “unknown”. It was “waiting for first reading” but that updated to “unknown”, presumably after the first reading between the oilpal sensor and the oilpal modem. Any ideas what I’m doing wrong? My template sensor code is:
  - platform: scrape
    resource: http://192.168.86.54/diag.htm
    name: OilPalData
    select: 'table:nth-of-type(2) td:nth-of-type(5)'
    unit_of_measurement: 'Litres'
    value_template: >-
      {% set modem_values = value.split(' ') %}
      {% set tank_temp = modem_values[1] %}
      {% if tank_temp != "Data" %}
        {% set tank_depth = modem_values[0] | int %}
        {% set tank_type = {
          "value": 2
        } %}
        {% set tank_dimensions = {
          "height": 142,    
          "radius": 58.65,
          "width": 69,
          "length": 165,
        } %}
        {% set tank_area = {
          "value": (3.1416 * (tank_dimensions.radius * tank_dimensions.radius) * tank_dimensions.height) / 1000,
        } %}
        {% if tank_type.value == 1 %}
          {% set tank_volume = {
            "value": (tank_dimensions.height - tank_depth) * tank_area.value / 100,
          } %}
        {% else %}
          {% set tank_volume = {
            "value": (tank_dimensions.height - tank_depth) * tank_dimensions.length * tank_dimensions.width / 1000,
          } %}
        {% endif %}
        {{ tank_volume.value | round (0) }}
      {% else %}
        {% if states.sensor.oilpaldata.state == "" %}
          Waiting for first reading
        {% else %}
          {{ states.sensor.oilpaldata.state }}
        {% endif %}
      {% endif %}
    scan_interval: 60
  • If I know the volume, do I need the other dimensions? Can I just simply set the tank_volume variable to “1040” and remove the other calculations, as per below?
  - platform: scrape
    resource: http://192.168.86.54/diag.htm
    name: OilPalDataq
    select: 'table:nth-of-type(2) td:nth-of-type(5)'
    unit_of_measurement: 'Litres'
    value_template: >-
      {% set modem_values = value.split(' ') %}
      {% set tank_temp = modem_values[1] %}
      {% if tank_temp != "Data" %}
        {% set tank_depth = modem_values[0] | int %}
        {% set tank_volume = "1040" %}
        {{ tank_volume.value | round (0) }}
      {% else %}
        {% if states.sensor.oilpaldata.state == "" %}
          Waiting for first reading
        {% else %}
          {{ states.sensor.oilpaldata.state }}
        {% endif %}
      {% endif %}
    scan_interval: 60

  • Would you mind sharing your yaml for the Apex Charts (post #32 above)? I think it looks great and is exactly what I’d like for my own dashboard!

Thanks again for sharing your code - I really appreciate it.

Hi @dunner I’ll come back to this in the morning, but your second code paste has completely removed any of the tank volume steps, so you definately aren’t going to get any values with that. You need your dimensions at the moment as the tank volume is calculated using those.

1 Like

Any update @c0rnflake? Thanks!

UPDATE: Switched to direct reception using an RTL-SDR dongle and rtl_433 for which there is rudimentary support for GFSK ultrasonic oil sensors.

Finally got around to implementing this. Thank you to everyone who’s contributed so far.

First: we have two tanks.

Second: our sensors also report temperature.

I implemented a scraper (based on scrapy) here: GitHub - markferry/tekelek-scraper: Scrape Tekelek 608A data to MQTT

It scrapes diag.htm (once) and publishes data for all sensors to MQTT.
(There are still hardcoded values for my test setup.)

The table headings disagree with the data. For example we get:

Device # RF Address #Rx Rx Time (h) Data Aux Bat [Cache] [FL Hi Lo Dif]
1 662 363 8/1/15 02:01 1177 50 0 [80 64 99 ]
2 282 157 8/1/15 01:57 No Data
3 0 0 0/0/0 00:00 No Data
4 0 0 0/0/0 00:00 No Data

In our case the Data field is actually temperature and Aux field is the depth reading.

What was interesting was decoding some of the cache values - noting that the high bits for temperature overlap the low bits for the depth reading.

Speed of sound varies with temperature increasing more-or-less ~0.6m/s per ⁰C.
So Tekelek record the depth reading at a resolution of 0.5cm leading to a (rather compact) adjustment for temperature. And that’s close enough:

Temp Actual Estimated
@-40⁰C 306.2 m/s 311.4 m/s
@ 0⁰C 331.4 m/s
@+40⁰C 354.7 m/s 351.4 m/s

I’m not sure now that the diag page makes any sense with multiple sensors.

Did a test and our ID 282 sensor was the only device transmitting yet the data is showing up on the first sensor line. Line 2 always shows No Data.

I think it’s buggy…

Has anyone tried setting oil pal up via ‘scrape’ (new Home Assistant 2022.12.1)?

Looked at it a few times, but havent gotten around to trying to port over from the legacy setup yet :frowning:

Am I getting the message correctly from the last couple of posts that the old code in the top post here won’t work on a new HA install

It works just fine upto and including 2023.1

Thanks very much. Means it’s user error on my part then.

If I’ve dropped the code into my configuration.yaml, updated the IP etc, then dropped in the card code but get “Entity not available: sensor.oilpaldata”

Are there dependencies I need to install or anything like that. If anyone has got a good guide in general to how this type of scraping works in HA I can take a look at that too instead of clogging up this thread?

If you check in Developer Tools/States, do any oilpal sensors exist?

Hi, just boarded the HA train, config.yaml wud not load the sensor data “scrappe not allowed”, and is disabled :thinking:
Please suggest any other way of integration if possible
Thank you

It’s because the scrape integration changed. I updated the first few llines of my sensor definition like this


scrape:
  - resource: http://192.168.10.8/diag.htm
    scan_interval: 60
    sensor:
    - name: OilPalData
      .....

Hope that helps

With all the changes and variations, would anyone be able to post an up to date yaml config for a horizontal cylinder tank. Myu understanding is cormatting etc has changed, and I have been trying to reformat/change my config and cant get it working.

Regards,
Eamon

Maybe someone can help if I give a bit more info. My config.yaml file throws an error when I add the oilpal scrape info. The error says
“Invalid config for [scrape]: [name] is an invalid option for [scrape]. Check: scrape->scrape->1->name. (See /config/configuration.yaml, line 18).”

and my config file is below. Would really appreciate some advice, stumped at the moment!

‘’’

Loads default set of integrations. Do not remove.

default_config:

Load frontend themes from the themes folder

frontend:
themes: !include_dir_merge_named themes

Text-to-speech

tts:

  • platform: google_translate

automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml

Example configuration.yaml entry

scrape:

  • resource: http://192.168.100.243/diag.htm
    scan_interval: 60
    sensor:

  • name: “OilPalData”
    select: ‘table:nth-of-type(2) td:nth-of-type(5)’
    unit_of_measurement: ‘Litres’
    value_template: >-
    {% set modem_values = value.split(’ ') %}
    {% set tank_temp = modem_values[1] %}
    {% if tank_temp != “Data” %}
    {% set tank_depth = modem_values[0] | int %}
    {% set tank_dimentions = {

    “height”: 106,

    “width”: 67,

    “length”: 175,

    } %}

    {% set tank_volume = {

    “value”: (tank_dimentions.height - tank_depth) * tank_dimentions.length * tank_dimentions.width / 1000,

    } %}

    {{ tank_volume.value | round (0) }}

    {% else %}

    {% if states.sensor.oilpaldata.state == “” %}

    Waiting for first reading

    {% else %}

    {{ states.sensor.oilpaldata.state }}

    {% endif %}

    {% endif %}

mqtt:
switch:
- name: “Sunset”
unique_id: “Sunset”
state_topic: “comfort2/flag1”
command_topic: “comfort2/flag1/set”
availability_topic: “comfort2/alarm/online”
payload_on: “0” #logic is opposite, comfort announces only if flag16 is 0
payload_off: “1”
payload_available: “1”
payload_not_available: “0”
binary_sensor:
- name: “Front Door”
unique_id: “front door”
state_topic: “comfort2/input1”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “Kitchen Door”
unique_id: “Kitchen door”
state_topic: “comfort2/input2”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “Back Door”
unique_id: “Back door”
state_topic: “comfort2/input3”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “Office Door”
unique_id: “Office door”
state_topic: “comfort2/input4”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “Hall Motion”
unique_id: “Hall Motion”
state_topic: “comfort2/input5”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “Corridoor Motion”
unique_id: “Corridoor Motion”
state_topic: “comfort2/input6”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “Kitchen Motion”
unique_id: “Kitchen Motion”
state_topic: “comfort2/input7”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “Den Motion”
unique_id: “Den Motion”
state_topic: “comfort2/input8”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “Utility Motion”
unique_id: “Utility Motion”
state_topic: “comfort2/input9”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “Office Motion”
unique_id: “Office motion”
state_topic: “comfort2/input10”
payload_on: “1”
payload_off: “0”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
- name: “Bathroom Motion”
unique_id: “Bathroom Motion”
state_topic: “comfort2/input11”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “Ciaran Motion”
unique_id: “Ciaran Motion”
state_topic: “comfort2/input12”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “Guest Motion”
unique_id: “Guest Motion”
state_topic: “comfort2/input13”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “Master Bedroom Motion”
unique_id: “Master Bedroom Motion”
state_topic: “comfort2/input14”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “En Suite Motion”
unique_id: “En Suite Motion”
state_topic: “comfort2/input15”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “En Suite Door”
unique_id: “En Suite Door”
state_topic: “comfort2/input16”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “Dressing Room Door”
unique_id: “Dressing Room Door”
state_topic: “comfort2/input17”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “Kelly Motion”
unique_id: “Kelly Motion”
state_topic: “comfort2/input18”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “Living Room Motion”
unique_id: “Living Room Motion”
state_topic: “comfort2/input19”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
- name: “En Suite Door”
unique_id: “En Suite door”
state_topic: “comfort2/input24”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
payload_on: “1”
payload_off: “0”
alarm_control_panel:
- name: “Comfort Alarm”
unique_id: “Comfort Alarm”
state_topic: “comfort2/alarm”
command_topic: “comfort2/alarm/set”
availability_topic: “comfort2/alarm/online”
payload_available: “1”
payload_not_available: “0”
code: “1234” #code can be different from Comfort’s
‘’’

Got a notification that oil pal monitoring was ceasing as of end of dec, so asked them if they could provide details of my tank configuration, thought this might be interesting as it shows unuseable capacity etc to make things a bit more accurate.

Might be of use to anyone interested in making it more accurate.

Im too stupid to change this correctly. I get


with this

Lines 51 to 87 in your config need to be indented by a further 2 spaces. That should fix it.