Skip to content

Commit

Permalink
feat: add init commit (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdraco authored Jan 21, 2024
1 parent 7ad6090 commit 5623211
Show file tree
Hide file tree
Showing 9 changed files with 746 additions and 99 deletions.
9 changes: 2 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,10 @@ jobs:
fail-fast: false
matrix:
python-version:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
os:
- ubuntu-latest
- windows-latest
- macOS-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -85,14 +80,14 @@ jobs:

# Do a dry run of PSR
- name: Test release
uses: python-semantic-release/python-semantic-release@v8.7.2
uses: bluetooth-devices/python-semantic-release@311
if: github.ref_name != 'main'
with:
root_options: --noop

# On main branch: actual PSR + upload to PyPI & GitHub
- name: Release
uses: python-semantic-release/python-semantic-release@v8.7.2
uses: bluetooth-devices/python-semantic-release@311
id: release
if: github.ref_name == 'main'
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/poetry-upgrade.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Upgrader
on:
workflow_dispatch:
schedule:
- cron: "51 21 26 * *"
- cron: "19 3 1 * *"

jobs:
upgrade:
Expand Down
286 changes: 206 additions & 80 deletions poetry.lock

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ packages = [
"Changelog" = "https://github.com/bluetooth-devices/leaone-ble/blob/main/CHANGELOG.md"

[tool.poetry.dependencies]
python = "^3.8"
python = "^3.11"
bluetooth-sensor-state-data = ">=1.6.2"
home-assistant-bluetooth = ">=1.10.4"
sensor-state-data = ">=2.18.0"
bluetooth-data-tools = ">=1.19.0"

[tool.poetry.group.dev.dependencies]
pytest = "^7.0"
Expand Down
36 changes: 35 additions & 1 deletion src/leaone_ble/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,35 @@
__version__ = "0.0.0"
"""
Parser for Leaone BLE advertisements.
This file is shamelessly copied from the following repository:
https://github.com/Ernst79/bleparser/blob/c42ae922e1abed2720c7fac993777e1bd59c0c93/package/bleparser/leaone.py
MIT License applies.
"""
from __future__ import annotations

from sensor_state_data import (
DeviceClass,
DeviceKey,
SensorDescription,
SensorDeviceInfo,
SensorUpdate,
SensorValue,
Units,
)

from .parser import LeaoneBluetoothDeviceData

__version__ = "0.1.1"

__all__ = [
"LeaoneBluetoothDeviceData",
"SensorDescription",
"SensorDeviceInfo",
"DeviceClass",
"DeviceKey",
"SensorUpdate",
"SensorDeviceInfo",
"SensorValue",
"Units",
]
3 changes: 0 additions & 3 deletions src/leaone_ble/main.py

This file was deleted.

124 changes: 124 additions & 0 deletions src/leaone_ble/parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
"""
Parser for Leaone BLE advertisements.
This file is shamelessly copied from the following repository:
https://github.com/Ernst79/bleparser/blob/c42ae922e1abed2720c7fac993777e1bd59c0c93/package/bleparser/xiaogui.py
MIT License applies.
"""
from __future__ import annotations

import logging
import struct

from bluetooth_data_tools import short_address
from bluetooth_sensor_state_data import BluetoothData
from home_assistant_bluetooth import BluetoothServiceInfo
from sensor_state_data import SensorLibrary

_LOGGER = logging.getLogger(__name__)


def address_to_bytes(address: str) -> bytes:
"""Return the address as bytes."""
return bytes([int(x, 16) for x in address.split(":")])


UNPACK_DATA = struct.Struct(">BHHHB").unpack

_DEVICE_TYPE_FROM_MODEL = {
0x20: "TZC4",
0x21: "TZC4",
0x24: "QJ-J",
0x25: "QJ-J",
0x30: "TZC4",
0x31: "TZC4",
}

LBS_TO_KGS = 0.45359237


class LeaoneBluetoothDeviceData(BluetoothData):
"""Data for Leaone BLE sensors."""

def _start_update(self, service_info: BluetoothServiceInfo) -> None:
"""Update from BLE advertisement data."""
_LOGGER.debug("Parsing Leaone BLE advertisement data: %s", service_info)
if (
not service_info.manufacturer_data
or service_info.service_data
or service_info.service_uuids
):
return
address = service_info.address
last_id = list(service_info.manufacturer_data)[-1]
last_data = service_info.manufacturer_data[last_id]
if len(last_data) != 13:
return

mac_trailer = last_data[-6:]
expected_mac = address_to_bytes(service_info.address)
if expected_mac != mac_trailer:
return

model = last_data[6]
if device_type := _DEVICE_TYPE_FROM_MODEL.get(model):
self.set_device_manufacturer("Leaone")
self.set_device_type(device_type)
name = f"{device_type} {short_address(address)}"
self.set_title(name)
self.set_device_name(name)
else:
return

changed_manufacturer_data = self.changed_manufacturer_data(service_info)
if not changed_manufacturer_data or len(changed_manufacturer_data) > 1:
# If len(changed_manufacturer_data) > 1 it means we switched
# ble adapters so we do not know which data is the latest
# and we need to wait for the next update.
return

last_id = list(changed_manufacturer_data)[-1]
data = (
int(last_id).to_bytes(2, byteorder="little")
+ changed_manufacturer_data[last_id]
)
xvalue = data[1:9]
(frame_cnt, weight, impedance, control, stabilized_byte) = UNPACK_DATA(xvalue)
self.set_precision(2)
packet_id = frame_cnt << 8 | stabilized_byte
self.update_predefined_sensor(SensorLibrary.PACKET_ID__NONE, packet_id)
if stabilized_byte in (0x20,): # KGS
self.update_predefined_sensor(
SensorLibrary.MASS_NON_STABILIZED__MASS_KILOGRAMS,
weight / 10,
"non_stabilized_mass",
)
elif stabilized_byte in (0x21,): # KGS
self.update_predefined_sensor(
SensorLibrary.MASS__MASS_KILOGRAMS, weight / 10
)
self.update_predefined_sensor(SensorLibrary.IMPEDANCE__OHM, impedance / 10)
elif stabilized_byte in (0x30,): # LBS
self.update_predefined_sensor(
SensorLibrary.MASS_NON_STABILIZED__MASS_KILOGRAMS,
(weight / 10) * LBS_TO_KGS,
"non_stabilized_mass",
)
elif stabilized_byte in (0x31,): # LBS
self.update_predefined_sensor(
SensorLibrary.MASS__MASS_KILOGRAMS,
(weight / 10) * LBS_TO_KGS,
)
self.update_predefined_sensor(SensorLibrary.IMPEDANCE__OHM, impedance / 10)
elif stabilized_byte in (0x24,): # KGS
self.update_predefined_sensor(
SensorLibrary.MASS_NON_STABILIZED__MASS_KILOGRAMS,
weight / 100,
"non_stabilized_mass",
)
elif stabilized_byte in (0x25,): # KGS
self.update_predefined_sensor(
SensorLibrary.MASS__MASS_KILOGRAMS, weight / 100
)
self.update_predefined_sensor(SensorLibrary.IMPEDANCE__OHM, impedance / 10)
6 changes: 0 additions & 6 deletions tests/test_main.py

This file was deleted.

Loading

0 comments on commit 5623211

Please sign in to comment.