Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial support for Senssun scale #1380

Merged
merged 2 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ This custom component for [Home Assistant](https://www.home-assistant.io) passiv
- Ruuvitag
- Sensirion
- SensorPush
- Senssun (Scale)
- SmartDry
- Switchbot
- Teltonika
Expand Down
5 changes: 5 additions & 0 deletions custom_components/ble_monitor/ble_parser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from .ruuvitag import parse_ruuvitag
from .sensirion import parse_sensirion
from .sensorpush import parse_sensorpush
from .senssun import parse_senssun
from .smartdry import parse_smartdry
from .switchbot import parse_switchbot
from .teltonika import parse_teltonika
Expand Down Expand Up @@ -422,6 +423,10 @@ def parse_advertisement(
# Laica
sensor_data = parse_laica(self, man_spec_data, mac)
break
elif comp_id == 0x0100 and data_len == 0x14:
# Senssun IF_B7
sensor_data = parse_senssun(self, man_spec_data, mac)
break

# Filter on part of the UUID16
elif man_spec_data[2] == 0xC0 and data_len == 0x10:
Expand Down
50 changes: 50 additions & 0 deletions custom_components/ble_monitor/ble_parser/senssun.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Parser for Senssun Scale BLE advertisements"""

import logging
from struct import unpack

from .helpers import to_mac, to_unformatted_mac

_LOGGER = logging.getLogger(__name__)


def read_stable(ctr1):
"""Parse Stable"""
return int((ctr1 & 0xA0) == 0xA0)

def parse_senssun(self, data: bytes, mac: str):
"""Parser for Senssun Scales."""
xvalue = data[13:19]

(division, weight, impedance, ctr1) = unpack(">bhhb", xvalue)
result = {
"type": "Senssun Smart Scale",
"firmware": "Senssun",
"mac": to_unformatted_mac(mac),
"data": True,
"impedance": impedance,
"weight": weight / 100.0,
"stabilized": read_stable(ctr1),
}

# Check for duplicate messages
packet_id = xvalue.hex()
try:
prev_packet = self.lpacket_ids[mac]
except KeyError:
# start with empty first packet
prev_packet = None
if prev_packet == packet_id:
# only process new messages
if self.filter_duplicates is True:
return None
self.lpacket_ids[mac] = packet_id
if prev_packet is None:
if self.filter_duplicates is True:
# ignore first message after a restart
return None

result.update({
"packet": packet_id,
})
return result
2 changes: 2 additions & 0 deletions custom_components/ble_monitor/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -1975,6 +1975,7 @@ class BLEMonitorBinarySensorEntityDescription(
'K6 Sensor Beacon' : [["temperature", "humidity", "acceleration", "voltage", "battery", "rssi"], [], []],
'DSL-C08' : [["battery", "rssi", "voltage"], [], ["lock", "childlock"]],
'SmartDry cloth dryer' : [["temperature", "humidity", "voltage", "battery", "shake", "rssi"], [], ["switch"]],
'Senssun Smart Scale' : [["rssi"], ["weight", "impedance"], []],
}

# Sensor manufacturer dictionary
Expand Down Expand Up @@ -2111,6 +2112,7 @@ class BLEMonitorBinarySensorEntityDescription(
'Laica Smart Scale' : 'Laica',
'K6 Sensor Beacon' : 'KKM',
'SmartDry cloth dryer' : 'SmartDry',
'Senssun Smart Scale' : 'Senssun',
}


Expand Down
28 changes: 28 additions & 0 deletions custom_components/ble_monitor/test/test_senssun_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""The tests for the Senssun ble_parser."""

import datetime

from ble_monitor.ble_parser import BleParser


class TestSenssun:
"""Tests for the Senssun parser"""

def test_Senssun_IF_B7(self):
"""Test Senssun parser for IF_B7."""
data_string = "043E2B0201030033B3C1937A181F020106060949465F423714FF0001020311187A93C1B333021A4500B4A1AB61C5"
data = bytes(bytearray.fromhex(data_string))

# pylint: disable=unused-variable
ble_parser = BleParser()
sensor_msg, tracker_msg = ble_parser.parse_raw_data(data)

assert sensor_msg["firmware"] == "Senssun"
assert sensor_msg["type"] == "Senssun Smart Scale"
assert sensor_msg["mac"] == "187A93C1B333"
assert sensor_msg["packet"] == "021a4500b4a1"
assert sensor_msg["data"]
assert sensor_msg["weight"] == 67.25
assert sensor_msg["stabilized"] == 1
assert sensor_msg["impedance"] == 180
assert sensor_msg["rssi"] == -59
17 changes: 17 additions & 0 deletions docs/_devices/Senssun_Smart_Scale.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
manufacturer: Senssun
name: Senssun Smart Scale
model: IF_B7
image: IF_B7.jpg
physical_description:
broadcasted_properties:
- weight
- impedance
- rssi
broadcasted_property_notes:
broadcast_rate:
active_scan:
encryption_key:
custom_firmware:
notes:
---
Binary file added docs/assets/images/IF_B7.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/config_params.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ Data from sensors with other addresses will be ignored. Default value: True

**Report unknown sensors**

(`Off`, `Acconeer`, `Air Mentor`, `Amazfit`, `ATC`, `BlueMaestro`, `Blustream`, `Brifit`, `BTHome`, `Chef iQ`, `Govee`, `Grundfos`, `HolyIOT`, `Hormann`, `HHCC`, `iNode`, `iBeacon`, `Jinou`, `Kegtron`, `Mi Scale`, `Mi Band`,`Mikrotik`, `Oras`, `Qingping`, `Relsib`, `rbaron`, `Ruuvitag`, `Sensirion`, `SensorPush`, `SmartDry`, `Switchbot`, `Teltonika`, `Thermoplus`, `Xiaogui`, `Xiaomi`, `Other` or `False`)(Optional) This option is needed primarily for those who want to request an implementation of device support that is not in the list of [supported sensors](devices). If you set this parameter to one of the sensor brands, then the component will log all messages from unknown devices of the specified brand to the Home Assistant log (`logger` component must be enabled at info level, see for instructions the [FAQ](faq#my-sensor-from-the-xiaomi-ecosystem-is-not-in-the-list-of-supported-ones-how-to-request-implementation)). Using a sensor brand might not catch all BLE advertisements.
(`Off`, `Acconeer`, `Air Mentor`, `Amazfit`, `ATC`, `BlueMaestro`, `Blustream`, `Brifit`, `BTHome`, `Chef iQ`, `Govee`, `Grundfos`, `HolyIOT`, `Hormann`, `HHCC`, `iNode`, `iBeacon`, `Jinou`, `Kegtron`, `Mi Scale`, `Mi Band`,`Mikrotik`, `Oras`, `Qingping`, `Relsib`, `rbaron`, `Ruuvitag`, `Sensirion`, `SensorPush`, `Senssun`, `SmartDry`, `Switchbot`, `Teltonika`, `Thermoplus`, `Xiaogui`, `Xiaomi`, `Other` or `False`)(Optional) This option is needed primarily for those who want to request an implementation of device support that is not in the list of [supported sensors](devices). If you set this parameter to one of the sensor brands, then the component will log all messages from unknown devices of the specified brand to the Home Assistant log (`logger` component must be enabled at info level, see for instructions the [FAQ](faq#my-sensor-from-the-xiaomi-ecosystem-is-not-in-the-list-of-supported-ones-how-to-request-implementation)). Using a sensor brand might not catch all BLE advertisements.

If you can't find the advertisements in this way, you can set this option to `Other`, which will result is all BLE advertisements being logged. You can also enable this option at device level. **Attention!** Enabling this option can lead to huge output to the Home Assistant log, especially when set to `Other`, do not enable it if you do not need it! If you know the MAC address of the sensor, its advised to set this option at device level. Details in the [FAQ](faq#my-sensor-from-the-xiaomi-ecosystem-is-not-in-the-list-of-supported-ones-how-to-request-implementation). Default value: `Off`

Expand Down
1 change: 1 addition & 0 deletions info.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ This custom component for [Home Assistant](https://www.home-assistant.io) passiv
- Ruuvitag
- Sensirion
- SensorPush
- Senssun
- SmartDry
- Switchbot
- Teltonika
Expand Down
Loading