Gas bottle (Mopeka)
The Mopeka sensor is the most demanding of them all — it does not send a level, only raw values. The percentage has to be calculated. We use exactly the same formulas the CampMatic app uses, so that app and Home Assistant show the same number.
What the sensor actually sends
The Mopeka measures upwards through the bottom of the bottle using ultrasound. What reaches you is the time of flight of that pulse — not the fill height, and certainly not a percentage:
campmatic/<GERAETE_ID>/mopeka/bottle_<SLOT_MOPEKA>/raw_tof time of flight, microseconds
campmatic/<GERAETE_ID>/mopeka/bottle_<SLOT_MOPEKA>/raw_t temperature byte (0–127)
campmatic/<GERAETE_ID>/mopeka/bottle_<SLOT_MOPEKA>/battery_raw battery as a raw byte
campmatic/<GERAETE_ID>/mopeka/bottle_<SLOT_MOPEKA>/quality measurement quality 0–3
campmatic/<GERAETE_ID>/mopeka/bottle_<SLOT_MOPEKA>/rssi signal strength in dBm
Creating the raw sensors
Append the following sensors under the existing mqtt: sensor: in your /config/packages/campmatic.yaml. Replace <GERAETE_ID> and <SLOT_MOPEKA> with your values.
- name: "Gas Bottle Time Of Flight"
unique_id: campmatic_<GERAETE_ID>_mopeka_<SLOT_MOPEKA>_tof
state_topic: "campmatic/<GERAETE_ID>/mopeka/bottle_<SLOT_MOPEKA>/raw_tof"
state_class: measurement
entity_category: diagnostic
icon: mdi:radar
expire_after: 2700
availability_topic: "campmatic/<GERAETE_ID>/status"
payload_available: "online"
payload_not_available: "offline"
- name: "Gas Bottle Temperature Byte"
unique_id: campmatic_<GERAETE_ID>_mopeka_<SLOT_MOPEKA>_rawt
state_topic: "campmatic/<GERAETE_ID>/mopeka/bottle_<SLOT_MOPEKA>/raw_t"
state_class: measurement
entity_category: diagnostic
expire_after: 2700
availability_topic: "campmatic/<GERAETE_ID>/status"
payload_available: "online"
payload_not_available: "offline"
- name: "Gas Bottle Temperature"
unique_id: campmatic_<GERAETE_ID>_mopeka_<SLOT_MOPEKA>_temp
state_topic: "campmatic/<GERAETE_ID>/mopeka/bottle_<SLOT_MOPEKA>/raw_t"
value_template: "{{ value | int - 40 }}"
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
expire_after: 2700
availability_topic: "campmatic/<GERAETE_ID>/status"
payload_available: "online"
payload_not_available: "offline"
- name: "Gas Bottle Sensor Battery"
unique_id: campmatic_<GERAETE_ID>_mopeka_<SLOT_MOPEKA>_batt
state_topic: "campmatic/<GERAETE_ID>/mopeka/bottle_<SLOT_MOPEKA>/battery_raw"
value_template: "{{ (value | float(0) / 32.0) | round(2) }}"
unit_of_measurement: "V"
device_class: voltage
state_class: measurement
entity_category: diagnostic
expire_after: 2700
availability_topic: "campmatic/<GERAETE_ID>/status"
payload_available: "online"
payload_not_available: "offline"
- name: "Gas Bottle Quality"
unique_id: campmatic_<GERAETE_ID>_mopeka_<SLOT_MOPEKA>_quality
state_topic: "campmatic/<GERAETE_ID>/mopeka/bottle_<SLOT_MOPEKA>/quality"
state_class: measurement
entity_category: diagnostic
icon: mdi:signal-cellular-2
expire_after: 2700
availability_topic: "campmatic/<GERAETE_ID>/status"
payload_available: "online"
payload_not_available: "offline"
Calculating height and level
Now the actual maths. It belongs under template: sensor: — if you do not have that section yet, create it once.
template:
- sensor:
- name: "Gas Bottle Level Height"
unique_id: campmatic_<GERAETE_ID>_mopeka_<SLOT_MOPEKA>_mm
unit_of_measurement: "mm"
state_class: measurement
icon: mdi:arrow-expand-vertical
availability: >-
{{ states('sensor.gas_bottle_time_of_flight') not in ['unknown','unavailable']
and states('sensor.gas_bottle_temperature_byte') not in ['unknown','unavailable'] }}
state: >-
{% set tof = states('sensor.gas_bottle_time_of_flight') | float(0) %}
{% set t = states('sensor.gas_bottle_temperature_byte') | float(0) %}
{{ (tof * (0.573045 - 0.002822 * t - 0.00000535 * t * t)) | round(1) }}
- name: "Gas Bottle Level"
unique_id: campmatic_<GERAETE_ID>_mopeka_<SLOT_MOPEKA>_level
unit_of_measurement: "%"
state_class: measurement
icon: mdi:propane-tank
availability: >-
{{ states('sensor.gas_bottle_level_height') not in ['unknown','unavailable'] }}
state: >-
{% set empty = 38 %}
{% set full = 333 %}
{% set mm = states('sensor.gas_bottle_level_height') | float(0) %}
{{ [[((mm - empty) / (full - empty) * 100), 0] | max, 100] | min | round(0) }}
sensor.gas_bottle_temperature_byte and not sensor.gas_bottle_temperature. Put the Celsius figure in there and you get values that look plausible — but are wrong. Entering your bottle
The two numbers empty and full in the level formula depend on your bottle. The empty value is the same for all of them, only the full value differs:
Bottle type empty full
6 kg steel 38 333
11 kg steel 38 358
14 kg steel 38 408
6 kg aluminium 38 300
11 kg aluminium 38 460
CampingGaz 907 38 130
US 20 lb 38 248
US 30 lb 38 381
US 40 lb 38 508
tank_type, for example EUROPE_6KG for the 6 kg steel bottle. Several bottles
With two Mopeka sensors you create the whole block a second time — with the second slot number and different names. Make sure the unique_id and the references inside the formulas move along too:
- name: "Gas Bottle Right Time Of Flight" # instead of "Gas Bottle Time Of Flight"
unique_id: campmatic_<GERAETE_ID>_mopeka_5_tof
state_topic: "campmatic/<GERAETE_ID>/mopeka/bottle_5/raw_tof"
...
# and in the formula as well:
{% set tof = states('sensor.gas_bottle_right_time_of_flight') | float(0) %}
Do not forget: after saving, check the configuration and restart Home Assistant.
- The configuration check reports no error
sensor.gas_bottle_level_heightshows a value in millimetressensor.gas_bottle_levelshows a plausible percentage- The quality reads 2 or 3 — at 0 or 1 the sensor is not seated properly