diff --git a/legacy/LYWSD03MMC.py b/legacy/LYWSD03MMC.py deleted file mode 100755 index e39eefe..0000000 --- a/legacy/LYWSD03MMC.py +++ /dev/null @@ -1,528 +0,0 @@ -#!/usr/bin/python3 -u -#!/home/openhabian/Python3/Python-3.7.4/python -u -#-u to unbuffer output. Otherwise when calling with nohup or redirecting output things are printed very lately or would even mixup - -from bluepy import btle -import argparse -import os -import re -from dataclasses import dataclass -from collections import deque -import threading -import time -import signal -import traceback -import math -import logging -import paho.mqtt.client as mqtt - -@dataclass -class Measurement: - temperature: float - humidity: int - voltage: float - calibratedHumidity: int = 0 - battery: int = 0 - timestamp: int = 0 - sensorname: str = "" - rssi: int = 0 - - def __eq__(self, other): #rssi may be different - if self.temperature == other.temperature and self.humidity == other.humidity and self.calibratedHumidity == other.calibratedHumidity and self.battery == other.battery and self.voltage == other.voltage and self.sensorname == other.sensorname: - return True - else: - return False - -measurements=deque() -#globalBatteryLevel=0 -previousMeasurement=Measurement(0,0,0,0,0,0,0,0) -identicalCounter=0 - -def signal_handler(sig, frame): - if args.atc: - disable_le_scan(sock) - os._exit(0) - -def watchDog_Thread(): - global unconnectedTime - global connected - global pid - while True: - logging.debug("watchdog_Thread") - logging.debug("unconnectedTime : " + str(unconnectedTime)) - logging.debug("connected : " + str(connected)) - logging.debug("pid : " + str(pid)) - now = int(time.time()) - if (unconnectedTime is not None) and ((now - unconnectedTime) > 60): #could also check connected is False, but this is more fault proof - pstree=os.popen("pstree -p " + str(pid)).read() #we want to kill only bluepy from our own process tree, because other python scripts have there own bluepy-helper process - logging.debug("PSTree: " + pstree) - try: - bluepypid=re.findall(r'bluepy-helper\((.*)\)',pstree)[0] #Store the bluepypid, to kill it later - except IndexError: #Should not happen since we're now connected - logging.debug("Couldn't find pid of bluepy-helper") - os.system("kill " + bluepypid) - logging.debug("Killed bluepy with pid: " + str(bluepypid)) - unconnectedTime = now #reset unconnectedTime to prevent multiple killings in a row - time.sleep(5) - - -def thread_SendingData(): - global previousMeasurement - global measurements - path = os.path.dirname(os.path.abspath(__file__)) - while True: - try: - mea = measurements.popleft() - if (mea == previousMeasurement and identicalCounter < args.skipidentical): #only send data when it has changed or X identical data has been skipped, ~10 pakets per minute, 50 pakets --> writing at least every 5 minutes - print("Measurements are identical don't send data\n") - identicalCounter+=1 - continue - identicalCounter=0 - fmt = "sensorname,temperature,humidity,voltage" #don't try to seperate by semicolon ';' os.system will use that as command seperator - if ' ' in mea.sensorname: - sensorname = '"' + mea.sensorname + '"' - else: - sensorname = mea.sensorname - params = sensorname + " " + str(mea.temperature) + " " + str(mea.humidity) + " " + str(mea.voltage) - if (args.TwoPointCalibration or args.offset): #would be more efficient to generate fmt only once - fmt +=",humidityCalibrated" - params += " " + str(mea.calibratedHumidity) - if (args.battery): - fmt +=",batteryLevel" - params += " " + str(mea.battery) - if (args.rssi): - fmt +=",rssi" - params += " " + str(mea.rssi) - params += " " + str(mea.timestamp) - fmt +=",timestamp" - -#""" cmd = path + "/" + args.callback + " " + fmt + " " + params -# print(cmd) -# ret = os.system(cmd)./L -# if (ret != 0): -# measurements.appendleft(mea) #put the measurement back -# print ("Data couln't be send to Callback, retrying...") -# time.sleep(5) #wait before trying again -# else: #data was sent -# previousMeasurement=Measurement(mea.temperature,mea.humidity,mea.voltage,mea.calibratedHumidity,mea.battery,0) #using copy or deepcopy requires implementation in the class definition -#""" - except IndexError: - #print("Keine Daten") - time.sleep(1) - except Exception as e: - print(e) - print(traceback.format_exc()) - -sock = None #from ATC -lastBLEPaketReceived = 0 -BLERestartCounter = 1 -def keepingLEScanRunning(): #LE-Scanning gets disabled sometimes, especially if you have a lot of BLE connections, this thread periodically enables BLE scanning again - global BLERestartCounter - while True: - time.sleep(1) - now = time.time() - if now - lastBLEPaketReceived > args.watchdogtimer: - print("Watchdog: Did not receive any BLE Paket within", int(now - lastBLEPaketReceived), "s. Restarting BLE scan. Count:", BLERestartCounter) - disable_le_scan(sock) - enable_le_scan(sock, filter_duplicates=False) - BLERestartCounter += 1 - print("") - time.sleep(5) #give some time to take effect - - -def calibrateHumidity2Points(humidity, offset1, offset2, calpoint1, calpoint2): - #offset1=args.offset1 - #offset2=args.offset2 - #p1y=args.calpoint1 - #p2y=args.calpoint2 - p1y=calpoint1 - p2y=calpoint2 - p1x=p1y - offset1 - p2x=p2y - offset2 - m = (p1y - p2y) * 1.0 / (p1x - p2x) # y=mx+b - #b = (p1x * p2y - p2x * p1y) * 1.0 / (p1y - p2y) - b = p2y - m * p2x #would be more efficient to do this calculations only once - humidityCalibrated=m*humidity + b - if (humidityCalibrated > 100 ): #with correct calibration this should not happen - humidityCalibrated = 100 - elif (humidityCalibrated < 0): - humidityCalibrated = 0 - humidityCalibrated=int(round(humidityCalibrated,0)) - return humidityCalibrated - - -mode="round" -class MyDelegate(btle.DefaultDelegate): - def __init__(self, params): - btle.DefaultDelegate.__init__(self) - # ... initialise here - - def handleNotification(self, cHandle, data): - global measurements - try: - measurement = Measurement(0,0,0,0,0,0,0,0) - if args.influxdb == 1: - measurement.timestamp = int((time.time() // 10) * 10) - else: - measurement.timestamp = int(time.time()) - temp=int.from_bytes(data[0:2],byteorder='little',signed=True)/100 - #print("Temp received: " + str(temp)) - if args.round: - #print("Temperatur unrounded: " + str(temp - - if args.debounce: - global mode - temp*=10 - intpart = math.floor(temp) - fracpart = round(temp - intpart,1) - #print("Fracpart: " + str(fracpart)) - if fracpart >= 0.7: - mode="ceil" - elif fracpart <= 0.2: #either 0.8 and 0.3 or 0.7 and 0.2 for best even distribution - mode="trunc" - #print("Modus: " + mode) - if mode=="trunc": #only a few times - temp=math.trunc(temp) - elif mode=="ceil": - temp=math.ceil(temp) - else: - temp=round(temp,0) - temp /=10. - #print("Debounced temp: " + str(temp)) - else: - temp=round(temp,1) - humidity=int.from_bytes(data[2:3],byteorder='little') - print("Temperature: " + str(temp)) - print("Humidity: " + str(humidity)) - voltage=int.from_bytes(data[3:5],byteorder='little') / 1000. - print("Battery voltage:",voltage,"V") - measurement.temperature = temp - measurement.humidity = humidity - measurement.voltage = voltage - measurement.sensorname = args.name - if args.battery: - #measurement.battery = globalBatteryLevel - batteryLevel = min(int(round((voltage - 2.1),2) * 100), 100) #3.1 or above --> 100% 2.1 --> 0 % - measurement.battery = batteryLevel - print("Battery level:",batteryLevel) - - - if args.offset: - humidityCalibrated = humidity + args.offset - print("Calibrated humidity: " + str(humidityCalibrated)) - measurement.calibratedHumidity = humidityCalibrated - - if args.TwoPointCalibration: - humidityCalibrated= calibrateHumidity2Points(humidity,args.offset1,args.offset2, args.calpoint1, args.calpoint2) - print("Calibrated humidity: " + str(humidityCalibrated)) - measurement.calibratedHumidity = humidityCalibrated - - if(args.callback): - measurements.append(measurement) - - - except Exception as e: - print("Fehler") - print(e) - print(traceback.format_exc()) - -# Initialisation ------- - -def connect(): - #print("Interface: " + str(args.interface)) - p = btle.Peripheral(adress,iface=args.interface) - val=b'\x01\x00' - p.writeCharacteristic(0x0038,val,True) #enable notifications of Temperature, Humidity and Battery voltage - p.writeCharacteristic(0x0046,b'\xf4\x01\x00',True) - p.withDelegate(MyDelegate("abc")) - return p - -# Main loop -------- -parser=argparse.ArgumentParser(allow_abbrev=False) -parser.add_argument("--device","-d", help="Set the device MAC-Address in format AA:BB:CC:DD:EE:FF",metavar='AA:BB:CC:DD:EE:FF') -parser.add_argument("--battery","-b", help="Get estimated battery level", metavar='', type=int, nargs='?', const=1) -parser.add_argument("--count","-c", help="Read/Receive N measurements and then exit script", metavar='N', type=int) -parser.add_argument("--interface","-i", help="Specifiy the interface number to use, e.g. 1 for hci1", metavar='N', type=int, default=0) -parser.add_argument("--unreachable-count","-urc", help="Exit after N unsuccessful connection tries", metavar='N', type=int, default=0) - - -rounding = parser.add_argument_group("Rounding and debouncing") -rounding.add_argument("--round","-r", help="Round temperature to one decimal place",action='store_true') -rounding.add_argument("--debounce","-deb", help="Enable this option to get more stable temperature values, requires -r option",action='store_true') - -offsetgroup = parser.add_argument_group("Offset calibration mode") -offsetgroup.add_argument("--offset","-o", help="Enter an offset to the reported humidity value",type=int) - -complexCalibrationGroup=parser.add_argument_group("2 Point Calibration") -complexCalibrationGroup.add_argument("--TwoPointCalibration","-2p", help="Use complex calibration mode. All arguments below are required",action='store_true') -complexCalibrationGroup.add_argument("--calpoint1","-p1", help="Enter the first calibration point",type=int) -complexCalibrationGroup.add_argument("--offset1","-o1", help="Enter the offset for the first calibration point",type=int) -complexCalibrationGroup.add_argument("--calpoint2","-p2", help="Enter the second calibration point",type=int) -complexCalibrationGroup.add_argument("--offset2","-o2", help="Enter the offset for the second calibration point",type=int) - -callbackgroup = parser.add_argument_group("Callback related arguments") -callbackgroup.add_argument("--callback","-call", help="Pass the path to a program/script that will be called on each new measurement") -callbackgroup.add_argument("--name","-n", help="Give this sensor a name reported to the callback script") -callbackgroup.add_argument("--skipidentical","-skip", help="N consecutive identical measurements won't be reported to callbackfunction",metavar='N', type=int, default=0) -callbackgroup.add_argument("--influxdb","-infl", help="Optimize for writing data to influxdb,1 timestamp optimization, 2 integer optimization",metavar='N', type=int, default=0) - -atcgroup = parser.add_argument_group("ATC mode related arguments") -atcgroup.add_argument("--atc","-a", help="Read the data of devices with custom ATC firmware flashed",action='store_true') -atcgroup.add_argument("--watchdogtimer","-wdt",metavar='X', type=int, help="Re-enable scanning after not receiving any BLE packet after X seconds") -atcgroup.add_argument("--devicelistfile","-df",help="Specify a device list file giving further details to devices") -atcgroup.add_argument("--onlydevicelist","-odl", help="Only read devices which are in the device list file",action='store_true') -atcgroup.add_argument("--rssi","-rs", help="Report RSSI via callback",action='store_true') - - -args=parser.parse_args() -if args.device: - if re.match("[0-9a-fA-F]{2}([:]?)[0-9a-fA-F]{2}(\\1[0-9a-fA-F]{2}){4}$",args.device): - adress=args.device - else: - print("Please specify device MAC-Address in format AA:BB:CC:DD:EE:FF") - os._exit(1) -elif not args.atc: - parser.print_help() - os._exit(1) - -if args.TwoPointCalibration: - if(not(args.calpoint1 and args.offset1 and args.calpoint2 and args.offset2)): - print("In 2 Point calibration you have to enter 4 points") - os._exit(1) - elif(args.offset): - print("Offset calibration and 2 Point calibration can't be used together") - os._exit(1) -if not args.name: - args.name = args.device - -if args.callback: - dataThread = threading.Thread(target=thread_SendingData) - dataThread.start() - -signal.signal(signal.SIGINT, signal_handler) - -if args.device: - - p=btle.Peripheral() - cnt=0 - - - connected=False - #logging.basicConfig(level=logging.DEBUG) - logging.basicConfig(level=logging.ERROR) - logging.debug("Debug: Starting script...") - pid=os.getpid() - bluepypid=None - unconnectedTime=None - connectionLostCounter=0 - - watchdogThread = threading.Thread(target=watchDog_Thread) - watchdogThread.start() - logging.debug("watchdogThread started") - - while True: - try: - if not connected: - #Bluepy sometimes hangs and makes it even impossible to connect with gatttool as long it is running - #on every new connection a new bluepy-helper is called - #we now make sure that the old one is really terminated. Even if it hangs a simple kill signal was sufficient to terminate it - # if bluepypid is not None: - # os.system("kill " + bluepypid) - # print("Killed possibly remaining bluepy-helper") - # else: - # print("bluepy-helper couldn't be determined, killing not allowed") - - print("Trying to connect to " + adress) - p=connect() - # logging.debug("Own PID: " + str(pid)) - # pstree=os.popen("pstree -p " + str(pid)).read() #we want to kill only bluepy from our own process tree, because other python scripts have there own bluepy-helper process - # logging.debug("PSTree: " + pstree) - # try: - # bluepypid=re.findall(r'bluepy-helper\((.*)\)',pstree)[0] #Store the bluepypid, to kill it later - # except IndexError: #Should not happen since we're now connected - # logging.debug("Couldn't find pid of bluepy-helper") - connected=True - unconnectedTime=None - - # if args.battery: - # if(cnt % args.battery == 0): - # print("Warning the battery option is deprecated, Aqara device always reports 99 % battery") - # batt=p.readCharacteristic(0x001b) - # batt=int.from_bytes(batt,byteorder="little") - # print("Battery-Level: " + str(batt)) - # globalBatteryLevel = batt - - - if p.waitForNotifications(2000): - # handleNotification() was called - - cnt += 1 - if args.count is not None and cnt >= args.count: - print(str(args.count) + " measurements collected. Exiting in a moment.") - p.disconnect() - time.sleep(5) - #It seems that sometimes bluepy-helper remains and thus prevents a reconnection, so we try killing our own bluepy-helper - pstree=os.popen("pstree -p " + str(pid)).read() #we want to kill only bluepy from our own process tree, because other python scripts have there own bluepy-helper process - bluepypid=0 - try: - bluepypid=re.findall(r'bluepy-helper\((.*)\)',pstree)[0] #Store the bluepypid, to kill it later - except IndexError: #Should normally occur because we're disconnected - logging.debug("Couldn't find pid of bluepy-helper") - if bluepypid != 0: - os.system("kill " + bluepypid) - logging.debug("Killed bluepy with pid: " + str(bluepypid)) - os._exit(0) - print("") - continue - except Exception as e: - print("Connection lost") - connectionLostCounter +=1 - if connected is True: #First connection abort after connected - unconnectedTime=int(time.time()) - connected=False - if args.unreachable_count != 0 and connectionLostCounter >= args.unreachable_count: - print("Maximum numbers of unsuccessful connections reaches, exiting") - os._exit(0) - time.sleep(1) - logging.debug(e) - logging.debug(traceback.format_exc()) - - print ("Waiting...") - # Perhaps do something else here - -elif args.atc: - print("Script started in ATC Mode") - print("----------------------------") - print("In this mode all devices within reach are read out, unless a namefile and --namefileonlydevices is specified.") - print("Also --name Argument is ignored, if you require names, please use --namefile.") - print("In this mode rounding and debouncing are not available, since ATC firmware sends out only one decimal place.") - print("ATC mode usually requires root rights. If you want to use it with normal user rights, \nplease execute \"sudo setcap cap_net_raw,cap_net_admin+eip $(eval readlink -f `which python3`)\"") - print("You have to redo this step if you upgrade your python version.") - print("----------------------------") - - import sys - import bluetooth._bluetooth as bluez - - from bluetooth_utils import (toggle_device, - enable_le_scan, parse_le_advertising_events, - disable_le_scan, raw_packet_to_str) - mqttserver = "192.168.0.114" - mqttclient = mqtt.Client("MiTemperature2") - - advCounter=dict() - sensors = dict() - if args.devicelistfile: - import configparser - if not os.path.exists(args.devicelistfile): - print ("Error specified device list file '",args.devicelistfile,"' not found") - os._exit(1) - sensors = configparser.ConfigParser() - sensors.read(args.devicelistfile) - - if args.onlydevicelist and not args.devicelistfile: - print("Error: --onlydevicelist requires --devicelistfile ") - os._exit(1) - - dev_id = args.interface # the bluetooth device is hci0 - toggle_device(dev_id, True) - - try: - sock = bluez.hci_open_dev(dev_id) - except: - print("Cannot open bluetooth device %i" % dev_id) - raise - - enable_le_scan(sock, filter_duplicates=False) - - try: - prev_data = None - - def le_advertise_packet_handler(mac, adv_type, data, rssi): - global lastBLEPaketReceived - if args.watchdogtimer: - lastBLEPaketReceived = time.time() - lastBLEPaketReceived = time.time() - #print("reveived BLE packet") - data_str = raw_packet_to_str(data) - ATCPaketMAC = data_str[10:22].upper() - macStr = mac.replace(":","").upper() - atcIdentifier = data_str[6:10].upper() - if(atcIdentifier == "1A18" and ATCPaketMAC == macStr) and not args.onlydevicelist or (atcIdentifier == "1A18" and mac in sensors): #only Data from ATC devices, double checked - advNumber = data_str[-2:] - if macStr in advCounter: - lastAdvNumber = advCounter[macStr] - else: - lastAdvNumber = None - if lastAdvNumber == None or lastAdvNumber != advNumber: - advCounter[macStr] = advNumber - print("BLE packet: %s %02x %s %d" % (mac, adv_type, data_str, rssi)) - #print("AdvNumber: ", advNumber) - #temp = data_str[22:26].encode('utf-8') - #temperature = int.from_bytes(bytearray.fromhex(data_str[22:26]),byteorder='big') / 10. - global measurements - measurement = Measurement(0,0,0,0,0,0,0,0) - if args.influxdb == 1: - measurement.timestamp = int((time.time() // 10) * 10) - else: - measurement.timestamp = int(time.time()) - - - #temperature = int(data_str[22:26],16) / 10. - temperature = int.from_bytes(bytearray.fromhex(data_str[22:26]),byteorder='big',signed=True) / 10. - print("Temperature: ", temperature) - humidity = int(data_str[26:28], 16) - print("Humidity: ", humidity) - batteryVoltage = int(data_str[30:34], 16) / 1000 - print ("Battery voltage:", batteryVoltage,"V") - print ("RSSI:", rssi, "dBm") - - if args.battery: - batteryPercent = int(data_str[28:30], 16) - print ("Battery:", batteryPercent,"%") - measurement.battery = batteryPercent - measurement.humidity = humidity - measurement.temperature = temperature - measurement.voltage = batteryVoltage - measurement.rssi = rssi - - if mac in sensors: - try: - measurement.sensorname = sensors[mac]["sensorname"] - except: - measurement.sensorname = mac - if "offset1" in sensors[mac] and "offset2" in sensors[mac] and "calpoint1" in sensors[mac] and "calpoint2" in sensors[mac]: - measurement.humidity = calibrateHumidity2Points(humidity,int(sensors[mac]["offset1"]),int(sensors[mac]["offset2"]),int(sensors[mac]["calpoint1"]),int(sensors[mac]["calpoint2"])) - print ("Humidity calibrated (2 points calibration): ", measurement.humidity) - elif "humidityOffset" in sensors[mac]: - measurement.humidity = humidity + int(sensors[mac]["humidityOffset"]) - print ("Humidity calibrated (offset calibration): ", measurement.humidity) - else: - measurement.sensorname = mac - - print ("MQTT publishing") - mqttclient.connect(mqttserver) - mqttclient.publish(("MiTemperature2/%s/temp" % measurement.sensorname), measurement.temperature) - mqttclient.publish(("MiTemperature2/%s/humidity" % measurement.sensorname), measurement.humidity) - mqttclient.publish(("MiTemperature2/%s/batterylevel" % measurement.sensorname), measurement.battery) - print ("MQTT done") - - - if(args.callback): - measurements.append(measurement) - #print("Length:", len(measurements)) - print("") - - if args.watchdogtimer: - keepingLEScanRunningThread = threading.Thread(target=keepingLEScanRunning) - keepingLEScanRunningThread.start() - logging.debug("keepingLEScanRunningThread started") - - - - # Blocking call (the given handler will be called each time a new LE - # advertisement packet is detected) - parse_le_advertising_events(sock, - handler=le_advertise_packet_handler, - debug=False) - except KeyboardInterrupt: - disable_le_scan(sock) diff --git a/legacy/bluetooth_utils.py b/legacy/bluetooth_utils.py deleted file mode 100644 index 529599a..0000000 --- a/legacy/bluetooth_utils.py +++ /dev/null @@ -1,421 +0,0 @@ -# -*- coding: utf-8 -*- -# This file is from https://github.com/colin-guyon/py-bluetooth-utils -# published under MIT License - -# MIT License - -# Copyright (c) 2020 Colin GUYON - -# 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. - -""" -Module containing some bluetooth utility functions (linux only). - -It either uses HCI commands using PyBluez, or does ioctl calls like it's -done in Bluez tools such as hciconfig. - -Main functions: - - toggle_device : enable or disable a bluetooth device - - set_scan : set scan type on a device ("noscan", "iscan", "pscan", "piscan") - - enable/disable_le_scan : enable BLE scanning - - parse_le_advertising_events : parse and read BLE advertisements packets - - start/stop_le_advertising : advertise custom data using BLE - -Bluez : http://www.bluez.org/ -PyBluez : http://karulis.github.io/pybluez/ - -The module was in particular inspired from 'iBeacon-Scanner-' -https://github.com/switchdoclabs/iBeacon-Scanner-/blob/master/blescan.py -and sometimes directly from the Bluez sources. -""" - -from __future__ import absolute_import -import sys -import struct -import fcntl -import array -import socket -from errno import EALREADY - -# import PyBluez -import bluetooth._bluetooth as bluez - -__all__ = ('toggle_device', 'set_scan', - 'enable_le_scan', 'disable_le_scan', 'parse_le_advertising_events', - 'start_le_advertising', 'stop_le_advertising', - 'raw_packet_to_str') - -LE_META_EVENT = 0x3E -LE_PUBLIC_ADDRESS = 0x00 -LE_RANDOM_ADDRESS = 0x01 - -OGF_LE_CTL = 0x08 -OCF_LE_SET_SCAN_PARAMETERS = 0x000B -OCF_LE_SET_SCAN_ENABLE = 0x000C -OCF_LE_CREATE_CONN = 0x000D -OCF_LE_SET_ADVERTISING_PARAMETERS = 0x0006 -OCF_LE_SET_ADVERTISE_ENABLE = 0x000A -OCF_LE_SET_ADVERTISING_DATA = 0x0008 - -SCAN_TYPE_PASSIVE = 0x00 -SCAN_FILTER_DUPLICATES = 0x01 -SCAN_DISABLE = 0x00 -SCAN_ENABLE = 0x01 - -# sub-events of LE_META_EVENT -EVT_LE_CONN_COMPLETE = 0x01 -EVT_LE_ADVERTISING_REPORT = 0x02 -EVT_LE_CONN_UPDATE_COMPLETE = 0x03 -EVT_LE_READ_REMOTE_USED_FEATURES_COMPLETE = 0x04 - -# Advertisement event types -ADV_IND = 0x00 -ADV_DIRECT_IND = 0x01 -ADV_SCAN_IND = 0x02 -ADV_NONCONN_IND = 0x03 -ADV_SCAN_RSP = 0x04 - -# Allow Scan Request from Any, Connect Request from Any -FILTER_POLICY_NO_WHITELIST = 0x00 -# Allow Scan Request from White List Only, Connect Request from Any -FILTER_POLICY_SCAN_WHITELIST = 0x01 -# Allow Scan Request from Any, Connect Request from White List Only -FILTER_POLICY_CONN_WHITELIST = 0x02 -# Allow Scan Request from White List Only, Connect Request from White List Only -FILTER_POLICY_SCAN_AND_CONN_WHITELIST = 0x03 - - -def toggle_device(dev_id, enable): - """ - Power ON or OFF a bluetooth device. - - :param dev_id: Device id. - :type dev_id: ``int`` - :param enable: Whether to enable of disable the device. - :type enable: ``bool`` - """ - hci_sock = socket.socket(socket.AF_BLUETOOTH, - socket.SOCK_RAW, - socket.BTPROTO_HCI) - print("Power %s bluetooth device %d" % ('ON' if enable else 'OFF', dev_id)) - # di = struct.pack("HbBIBBIIIHHHH10I", dev_id, *((0,) * 22)) - # fcntl.ioctl(hci_sock.fileno(), bluez.HCIGETDEVINFO, di) - req_str = struct.pack("H", dev_id) - request = array.array("b", req_str) - try: - fcntl.ioctl(hci_sock.fileno(), - bluez.HCIDEVUP if enable else bluez.HCIDEVDOWN, - request[0]) - except IOError as e: - if e.errno == EALREADY: - print("Bluetooth device %d is already %s" % ( - dev_id, 'enabled' if enable else 'disabled')) - else: - raise - finally: - hci_sock.close() - - -# Types of bluetooth scan -SCAN_DISABLED = 0x00 -SCAN_INQUIRY = 0x01 -SCAN_PAGE = 0x02 - - -def set_scan(dev_id, scan_type): - """ - Set scan type on a given bluetooth device. - - :param dev_id: Device id. - :type dev_id: ``int`` - :param scan_type: One of - ``'noscan'`` - ``'iscan'`` - ``'pscan'`` - ``'piscan'`` - :type scan_type: ``str`` - """ - hci_sock = socket.socket(socket.AF_BLUETOOTH, - socket.SOCK_RAW, - socket.BTPROTO_HCI) - if scan_type == "noscan": - dev_opt = SCAN_DISABLED - elif scan_type == "iscan": - dev_opt = SCAN_INQUIRY - elif scan_type == "pscan": - dev_opt = SCAN_PAGE - elif scan_type == "piscan": - dev_opt = SCAN_PAGE | SCAN_INQUIRY - else: - raise ValueError("Unknown scan type %r" % scan_type) - - req_str = struct.pack("HI", dev_id, dev_opt) - print("Set scan type %r to bluetooth device %d" % (scan_type, dev_id)) - try: - fcntl.ioctl(hci_sock.fileno(), bluez.HCISETSCAN, req_str) - finally: - hci_sock.close() - - -def raw_packet_to_str(pkt): - """ - Returns the string representation of a raw HCI packet. - """ - if sys.version_info > (3, 0): - return ''.join('%02x' % struct.unpack("B", bytes([x]))[0] for x in pkt) - else: - return ''.join('%02x' % struct.unpack("B", x)[0] for x in pkt) - - -def enable_le_scan(sock, interval=0x0800, window=0x0800, - filter_policy=FILTER_POLICY_NO_WHITELIST, - filter_duplicates=True): - """ - Enable LE passive scan (with filtering of duplicate packets enabled). - - :param sock: A bluetooth HCI socket (retrieved using the - ``hci_open_dev`` PyBluez function). - :param interval: Scan interval. - :param window: Scan window (must be less or equal than given interval). - :param filter_policy: One of - ``FILTER_POLICY_NO_WHITELIST`` (default value) - ``FILTER_POLICY_SCAN_WHITELIST`` - ``FILTER_POLICY_CONN_WHITELIST`` - ``FILTER_POLICY_SCAN_AND_CONN_WHITELIST`` - - .. note:: Scan interval and window are to multiply by 0.625 ms to - get the real time duration. - """ - print("Enable LE scan") - own_bdaddr_type = LE_PUBLIC_ADDRESS # does not work with LE_RANDOM_ADDRESS - cmd_pkt = struct.pack(" 31: - raise ValueError("data is too long (%d but max is 31 bytes)", - data_length) - cmd_pkt = struct.pack("/dev/null 2>&1 && pwd )" -#$DIR/LYWSD03MMC.py -d -b 1000 -r --debounce --skipidentical 50 --name MySensor --callback sendToMQTT - -#mosquitto_pub -h mqtt.host -t "MiTemperature2/$2/temp" -u mqtt.username -P mqtt.passwd -i "mibridge" -m "$3" -#mosquitto_pub -h mqtt.host -t "MiTemperature2/$2/humidity" -u mqtt.username -P mqtt.passwd -i "mibridge" -m "$4" -#mosquitto_pub -h mqtt.host -t "MiTemperature2/$2/batteryvoltage" -u mqtt.username -P mqtt.passwd -i "mibridge" -m "$5" -#mosquitto_pub -h mqtt.host -t "MiTemperature2/$2/batterylevel" -u mqtt.username -P mqtt.passwd -i "mibridge" -m "$6" - -mosquitto_pub -h 192.168.0.114 -t "MiTemperature2/$2/temp" -u hasse -P casablanca -i "mibridge" -m "$3" -mosquitto_pub -h 192.168.0.114 -t "MiTemperature2/$2/humidity" -u hasse -P casablanca -i "mibridge" -m "$4" -mosquitto_pub -h 192.168.0.114 -t "MiTemperature2/$2/batteryvoltage" -u hasse -P casablanca -i "mibridge" -m "$5" -mosquitto_pub -h 192.168.0.114 -t "MiTemperature2/$2/batterylevel" -u hasse -P casablanca -i "mibridge" -m "$6" diff --git a/legacy/sensorer.ini b/legacy/sensorer.ini deleted file mode 100644 index 03c99dc..0000000 --- a/legacy/sensorer.ini +++ /dev/null @@ -1,26 +0,0 @@ -[A4:C1:38:98:7B:B6] -sensorname=mi_temp_1 - -[A4:C1:38:29:03:0D] -sensorname=mi_temp_2 - -[A4:C1:38:62:CA:83] -sensorname=mi_temp_3 - -[A4:C1:38:D5:EA:63] -sensorname=mi_temp_4 - -[A4:C1:38:7C:9C:63] -sensorname=mi_temp_5 - -[A4:C1:38:68:2C:DA] -sensorname=mi_temp_6 - -[A4:C1:38:AD:74:2B] -sensorname=mi_temp_7 - -[A4:C1:38:46:9F:D1] -sensorname=mi_temp_8 - - - diff --git a/legacy/sensorer.sh b/legacy/sensorer.sh deleted file mode 100755 index 6ee7206..0000000 --- a/legacy/sensorer.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -# körs vid boot - -tmux new-session -d -s sensorer '/home/pi/sensorpajen/LYWSD03MMC.py -a -wdt 5 --devicelistfile sensorer.ini --callback yes --battery' -tmux detach -s sensorer diff --git a/legacy/startup.sh b/legacy/startup.sh deleted file mode 100755 index 988bc89..0000000 --- a/legacy/startup.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -tmux start-server - -tmux new-session -d -s sensorer -n sensorer -d 'cd /home/pi/sensorpajen; ./LYWSD03MMC.py -a -wdt 5 --devicelistfile sensorer.ini --callback yes --battery' -tmux split-window -t sensorer:0 'cd /home/pi/pirate_audio; ./loop.sh' -tmux split-window -t sensorer:0 'cd /home/pi/pirate_audio; ./buttons.py' - -tmux select-layout -t sensorer:0 tiled -