diff --git a/src/Xiaomi_Scale.py b/src/Xiaomi_Scale.py index c07b586..cab8de0 100644 --- a/src/Xiaomi_Scale.py +++ b/src/Xiaomi_Scale.py @@ -33,12 +33,12 @@ MISCALE_MAC = os.getenv('MISCALE_MAC', '') MQTT_USERNAME = os.getenv('MQTT_USERNAME', '') MQTT_PASSWORD = os.getenv('MQTT_PASSWORD', '') MQTT_HOST = os.getenv('MQTT_HOST', '127.0.0.1') -MQTT_PORT = os.getenv('MQTT_PORT', 1883) -MQTT_TIMEOUT = os.getenv('MQTT_TIMEOUT', 60) +MQTT_PORT = int(os.getenv('MQTT_PORT', 1883)) +MQTT_TIMEOUT = int(os.getenv('MQTT_TIMEOUT', 60)) MQTT_PREFIX = os.getenv('MQTT_PREFIX', '') +OLD_MEASURE = '' # User Variables... - USER1_GT = int(os.getenv('USER1_GT', '70')) # If the weight is greater than this number, we'll assume that we're weighing User #1 USER1_SEX = os.getenv('USER1_SEX', 'male') USER1_NAME = os.getenv('USER1_NAME', 'David') # Name of the user @@ -58,7 +58,6 @@ USER3_DOB = os.getenv('USER3_DOB', '1988-01-01') # DOB (in yyyy-mm-dd format) class ScanProcessor(): - def GetAge(self, d1): d1 = datetime.strptime(d1, "%Y-%m-%d") d2 = datetime.strptime(datetime.today().strftime('%Y-%m-%d'),'%Y-%m-%d') @@ -69,55 +68,48 @@ class ScanProcessor(): self.connected = False self._start_client() + def handleDiscovery(self, dev, isNewDev, isNewData): + global OLD_MEASURE if dev.addr == MISCALE_MAC.lower() and isNewDev: - # print (' Device: %s (%s), %d dBm %s. ' % - # ( - # ANSI_WHITE + dev.addr + ANSI_OFF, - # dev.addrType, - # dev.rssi, - # ('' if dev.connectable else '(not connectable)')) - # , end='') for (sdid, desc, data) in dev.getScanData(): ### Xiaomi V1 Scale ### if data.startswith('1d18') and sdid == 22: measunit = data[4:6] measured = int((data[8:10] + data[6:8]), 16) * 0.01 unit = '' - if measunit.startswith(('03', 'b3')): unit = 'lbs' if measunit.startswith(('12', 'b2')): unit = 'jin' if measunit.startswith(('22', 'a2')): unit = 'kg' ; measured = measured / 2 - if unit: - print('') - self._publish(round(measured, 2), unit, "", "") - else: - print("Scale is sleeping.") + if OLD_MEASURE != round(measured, 2): + print('') + self._publish(round(measured, 2), unit, 0, "", "") + OLD_MEASURE = round(measured, 2) ### Xiaomi V2 Scale ### if data.startswith('1b18') and sdid == 22: + data2 = bytes.fromhex(data[4:]) + ctrlByte0 = data2[0] + ctrlByte1 = data2[1] + isStabilized = ctrlByte1 & (1<<5) + hasImpedance = ctrlByte1 & (1<<1) + measunit = data[4:6] measured = int((data[28:30] + data[26:28]), 16) * 0.01 unit = '' - if measunit == "03": unit = 'lbs' if measunit == "02": unit = 'kg' ; measured = measured / 2 mitdatetime = datetime.strptime(str(int((data[10:12] + data[8:10]), 16)) + " " + str(int((data[12:14]), 16)) +" "+ str(int((data[14:16]), 16)) +" "+ str(int((data[16:18]), 16)) +" "+ str(int((data[18:20]), 16)) +" "+ str(int((data[20:22]), 16)), "%Y %m %d %H %M %S") miimpedance = str(int((data[24:26] + data[22:24]), 16)) - - - - if unit: - print('') - self._publish(round(measured, 2), unit, str(mitdatetime), miimpedance) - else: - print("Scale is sleeping.") - + if unit and isStabilized: + if OLD_MEASURE != round(measured, 2) + int(miimpedance): + print('') + self._publish(round(measured, 2), unit, str(datetime.today().strftime('%Y-%m-%d-%H:%M:%S')), hasImpedance, miimpedance) + OLD_MEASURE = round(measured, 2) + int(miimpedance) if not dev.scanData: print ('\t(no data)') - print def _start_client(self): self.mqtt_client = mqtt.Client() @@ -125,16 +117,16 @@ class ScanProcessor(): def _on_connect(client, _, flags, return_code): self.connected = True - #print("MQTT connection returned result: %s" % mqtt.connack_string(return_code)) + sys.stdout.write("MQTT connection: %s\n" % mqtt.connack_string(return_code)) self.mqtt_client.on_connect = _on_connect - self.mqtt_client.connect(MQTT_HOST, MQTT_PORT, MQTT_TIMEOUT) self.mqtt_client.loop_start() - def _publish(self, weight, unit, mitdatetime, miimpedance): + def _publish(self, weight, unit, mitdatetime, hasImpedance, miimpedance): if not self.connected: - raise Exception('not connected to MQTT server') + sys.stderr.write('Not connected to MQTT server\n') + exit() if int(weight) > USER1_GT: user = USER1_NAME height = USER1_HEIGHT @@ -157,7 +149,7 @@ class ScanProcessor(): message += ',"Basal Metabolism":"' + "{:.2f}".format(lib.getBMR()) + '"' message += ',"Visceral Fat":"' + "{:.2f}".format(lib.getVisceralFat()) + '"' - if miimpedance: + if hasImpedance: lib = Xiaomi_Scale_Body_Metrics.bodyMetrics(weight, height, age, sex, int(miimpedance)) message += ',"Lean Body Mass":"' + "{:.2f}".format(lib.getLBMCoefficient()) + '"' message += ',"Body Fat":"' + "{:.2f}".format(lib.getFatPercentage()) + '"' @@ -165,19 +157,25 @@ class ScanProcessor(): message += ',"Bone Mass":"' + "{:.2f}".format(lib.getBoneMass()) + '"' message += ',"Muscle Mass":"' + "{:.2f}".format(lib.getMuscleMass()) + '"' message += ',"Protein":"' + "{:.2f}".format(lib.getProteinPercentage()) + '"' - self.mqtt_client.publish(MQTT_PREFIX + '/' + user, weight, qos=1, retain=True) message += ',"TimeStamp":"' + mitdatetime + '"' message += '}' self.mqtt_client.publish(MQTT_PREFIX + '/' + user + '/weight', message, qos=1, retain=True) - print('\tSent data to topic %s: %s' % (MQTT_PREFIX + '/' + user + '/weight', message)) + sys.stdout.write('Sent data to topic %s: %s' % (MQTT_PREFIX + '/' + user + '/weight', message + '\n')) def main(): - # while(True): + sys.stdout.write(' \n') + sys.stdout.write('-------------------------------------\n') + sys.stdout.write('Starting Xiaomi mi Scale...\n') scanner = btle.Scanner().withDelegate(ScanProcessor()) - - devices = scanner.scan(5) + while True: + # try: + scanner.scan(5) + # except: + # sys.stderr.write("Error while running the script, continuing. If you see this message too often/constantly there is probably a real issue...\n") + # pass + time.sleep(1) if __name__ == "__main__": - main() + main() \ No newline at end of file