Skip to content

Commit

Permalink
Merge pull request #43 from 8none1/thermobeacon_support
Browse files Browse the repository at this point in the history
Add support for ThermoBeacon temperature and humidity sensors
  • Loading branch information
frawau authored Dec 6, 2021
2 parents dc41df4 + 5e81d70 commit fa4bda4
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 0 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ You get
Temperature info {'mac address': 'a4:c1:38:40:52:38', 'temperature': 2.8, 'humidity': 62, 'battery': 72, 'battery_volts': 2.863, 'counter': 103, 'rssi': -76}
Temperature info {'mac address': 'a4:c1:38:40:52:38', 'temperature': 2.8, 'humidity': 62, 'battery': 72, 'battery_volts': 2.863, 'counter': 103, 'rssi': -77}

To check ThermoBeacon sensors

python3 -m aioblescan -T

You get

Temperature info {'mac address': '19:c4:00:00:0f:5d', 'max_temperature': 27.0625, 'min_temperature': 21.75, 'max_temp_ts': 0, 'min_temp_ts': 2309}
Temperature info {'mac address': '19:c4:00:00:0f:5d', 'temperature': 21.75, 'humidity': 49.5, 'battery_volts': 3234, 'counter': 2401, 'rssi': -67}

For a generic advertise packet scanning

python3 -m aioblescan
Expand Down
13 changes: 13 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,19 @@ You get
Temperature info {'mac address': 'a4:c1:38:40:52:38', 'temperature': 2.8, 'humidity': 62, 'battery': 72, 'battery_volts': 2.863, 'counter': 103, 'rssi': -76}
Temperature info {'mac address': 'a4:c1:38:40:52:38', 'temperature': 2.8, 'humidity': 62, 'battery': 72, 'battery_volts': 2.863, 'counter': 103, 'rssi': -77}

To check ThermoBeacon sensors

::

python3 -m aioblescan -T

You get

::
Temperature info {'mac address': '19:c4:00:00:0f:5d', 'max_temperature': 27.0625, 'min_temperature': 21.75, 'max_temp_ts': 0, 'min_temp_ts': 2309}
Temperature info {'mac address': '19:c4:00:00:0f:5d', 'temperature': 21.75, 'humidity': 49.5, 'battery_volts': 3234, 'counter': 2401, 'rssi': -67}


For a generic advertise packet scanning

::
Expand Down
14 changes: 14 additions & 0 deletions aioblescan/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from aioblescan.plugins import EddyStone
from aioblescan.plugins import RuuviWeather
from aioblescan.plugins import ATCMiThermometer
from aioblescan.plugins import ThermoBeacon

# global
opts = None
Expand Down Expand Up @@ -79,6 +80,12 @@ def my_process(data):
if xx:
print("Temperature info {}".format(xx))
return
if opts.thermobeacon:
noopt = False
xx = ThermoBeacon().decode(ev)
if xx:
print("Temperature info {}".format(xx))
return
if noopt:
ev.show(0)

Expand Down Expand Up @@ -115,6 +122,13 @@ def main(args=None):
default=False,
help="Look only for ATC_MiThermometer tag messages",
)
parser.add_argument(
"-T",
"--thermobeacon",
action="store_true",
default=False,
help="Look only for ThermoBeacon messages",
)
parser.add_argument(
"-R",
"--raw",
Expand Down
1 change: 1 addition & 0 deletions aioblescan/plugins/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .eddystone import EddyStone
from .ruuviweather import RuuviWeather
from .atcmithermometer import ATCMiThermometer
from .thermobeacon import ThermoBeacon
78 changes: 78 additions & 0 deletions aioblescan/plugins/thermobeacon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
#
# This file deals with Thermobeacon formatted messages
#
# Copyright (c) 2021 Will Cooke @8none1
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies
# or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
# IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE


def parse(packet):
peer = packet.retrieve("peer")
rssi = packet.retrieve("rssi")
uuid = packet.retrieve("Incomplete uuids")
payload = packet.retrieve("Manufacturer Specific Data")

if peer and rssi and payload and uuid:
uuid = uuid[0].lonbytes[0].val
payload = payload[0].payload[1].val

if b"\xff\xf0" == uuid:
mac = peer[0].val
rssi = rssi[0].val
mac_in_payload = ":".join("%02x" % x for x in payload[7:1:-1])
if mac == mac_in_payload:
return parse_payload(mac, rssi, payload)

def parse_payload(mac, rssi, payload):
if len(payload) == 18:
battery_volts = int.from_bytes(payload[8:10], "little")
temp = int.from_bytes(payload[10:12], "little", signed=True) / 16.0
humidity = int.from_bytes(payload[12:14], "little", signed=True) / 16.0
counter = int.from_bytes(payload[14:18], "little")
return {
"mac address": mac,
"temperature": temp,
"humidity": humidity,
"battery_volts": battery_volts,
"counter": counter,
"rssi": rssi,
}
elif len(payload) == 20:
max_temp = int.from_bytes(payload[8:10], "little") / 16.0
max_temp_ts = int.from_bytes(payload[10:14], "little")
min_temp = int.from_bytes(payload[14:16], "little") / 16.0
min_temp_ts = int.from_bytes(payload[16:20], "little")
return {
"mac address": mac,
"max_temperature": max_temp,
"min_temperature": min_temp,
"max_temp_ts": max_temp_ts,
"min_temp_ts": min_temp_ts
}
else:
return False

class ThermoBeacon(object):
"""Class defining the content of a ThermoBeacon advertisement."""

def decode(self, packet):
result = parse(packet)
if result:
return result

0 comments on commit fa4bda4

Please sign in to comment.