From 0e842e4ed9f3bfce4d455f75b96bae78ca6b5957 Mon Sep 17 00:00:00 2001 From: dheeppr15lap Date: Sat, 7 Dec 2024 12:50:46 +1100 Subject: [PATCH 1/2] base file --- .gitignore | 1 + basejun1_bt.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 .gitignore create mode 100644 basejun1_bt.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9e3d04c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +venv* diff --git a/basejun1_bt.py b/basejun1_bt.py new file mode 100644 index 0000000..d8ec8ca --- /dev/null +++ b/basejun1_bt.py @@ -0,0 +1,36 @@ +import asyncio +import bluetooth +from bleak import BleakClient + +JUNTEK_UUID = "0000ffe1-0000-1000-8000-00805f9b34fb" + +async def read_juntek_data(address): + async with BleakClient(address) as client: + while True: + try: + data = await client.read_gatt_char(JUNTEK_UUID) + decoded_data = data.decode('utf-8') + voltage, current, power = parse_juntek_data(decoded_data) + print(f"Voltage: {voltage}V, Current: {current}A, Power: {power}W") + await asyncio.sleep(1) + except Exception as e: + print(f"Error: {e}") + break + +def parse_juntek_data(data): + # Parse the data string based on Juntek's protocol + # This is a simplified example and may need adjustment + parts = data.split(',') + voltage = float(parts[0]) + current = float(parts[1]) + power = float(parts[2]) + return voltage, current, power + +def main(): + #juntek_address = "XX:XX:XX:XX:XX:XX" # Replace with your Juntek device's Bluetooth address + juntek_address = "84:C2:E4:44:59:59" # Replace with your Juntek device's Bluetooth address + + asyncio.run(read_juntek_data(juntek_address)) + +if __name__ == "__main__": + main() \ No newline at end of file From f7791ed03066595dc10c888531473280bbd50e13 Mon Sep 17 00:00:00 2001 From: dheeprpi Date: Sat, 7 Dec 2024 18:55:15 +1100 Subject: [PATCH 2/2] interim commit bluetooth utils --- .gitignore | 3 ++ BTjuntek.py | 11 ++++---- basejun1_bt.py | 5 ++-- basejun2_bt.py | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ basejun3_bt.py | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ config.py | 5 ++-- top5ble.py | 23 +++++++++++++++ 7 files changed, 189 insertions(+), 9 deletions(-) create mode 100644 basejun2_bt.py create mode 100644 basejun3_bt.py create mode 100644 top5ble.py diff --git a/.gitignore b/.gitignore index 9e3d04c..aefc79c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ venv* +__pycache* +*.txt + diff --git a/BTjuntek.py b/BTjuntek.py index 56609a6..cf6428f 100644 --- a/BTjuntek.py +++ b/BTjuntek.py @@ -173,6 +173,8 @@ def _callback(self, sender, data): key = params_keys[position] values[key] = value_str + + print(values) # check if dir_of_current exist if not asign if charging or dischargin exist if "dir_of_current" not in values and "charging" not in check: if "discharge" in values and "charge" not in values: @@ -233,7 +235,7 @@ def _callback(self, sender, data): logger.debug(values) - + print(values) #End of BLESNIFF Plug @@ -263,13 +265,13 @@ def _callback(self, sender, data): f"DISCOVERY_PUB=homeassistant/sensor/{entry['object_id']}/config\n" + "PL={json.dumps(entry)}\n" ) - publish.single( + ''' publish.single( topic=f"homeassistant/sensor/{entry['object_id']}/config", payload=json.dumps(entry), retain=True, hostname=config.MQTT_HOST, auth=auth, - ) + ) ''' self.discovery_info_sent = True @@ -280,7 +282,7 @@ def _callback(self, sender, data): if not args.quiet: print(f"{k} = {v}") - publish.multiple(mqtt_msgs, hostname=config.MQTT_HOST, auth=auth) + # publish.multiple(mqtt_msgs, hostname=config.MQTT_HOST, auth=auth) logger.info("Published updated sensor stats to MQTT") @@ -289,7 +291,6 @@ def _callback(self, sender, data): - if hasattr(config, "JT_LOG_FILE"): logging.basicConfig( filename=config.JT_LOG_FILE, diff --git a/basejun1_bt.py b/basejun1_bt.py index d8ec8ca..aaaf385 100644 --- a/basejun1_bt.py +++ b/basejun1_bt.py @@ -1,8 +1,9 @@ import asyncio -import bluetooth +# import bluetooth from bleak import BleakClient JUNTEK_UUID = "0000ffe1-0000-1000-8000-00805f9b34fb" +#JUNTEK_UUID = "ae656aea-86c2-d654-f73b-d3f9cc15a9d6" async def read_juntek_data(address): async with BleakClient(address) as client: @@ -33,4 +34,4 @@ def main(): asyncio.run(read_juntek_data(juntek_address)) if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/basejun2_bt.py b/basejun2_bt.py new file mode 100644 index 0000000..f14db11 --- /dev/null +++ b/basejun2_bt.py @@ -0,0 +1,75 @@ +import asyncio +from bleak import BleakClient, BleakScanner + +JUNTEK_UUID = "0000ffe1-0000-1000-8000-00805f9b34fb" + +async def connect_juntek(address): + device = await BleakScanner.find_device_by_address(address) + if not device: + print(f"Device with address {address} not found") + return + + async with BleakClient(device) as client: + print(f"Connected to {device.name}") + + while True: + try: + data = await client.read_gatt_char(JUNTEK_UUID) + decoded_data = data.decode('utf-8') + parsed_data = parse_juntek_data(decoded_data) + print_data(parsed_data) + await asyncio.sleep(1) + except Exception as e: + print(f"Error: {e}") + break + +def parse_juntek_data(data): + parts = data.split(',') + return { + 'voltage': float(parts[2]) / 100, + 'current': float(parts[3]) / 100, + 'remaining_capacity': float(parts[4]) / 100, + 'cumulative_capacity': float(parts[5]) / 100, + 'watt_hours': float(parts[6]) / 10000, + 'temperature': float(parts[8]) - 100, + 'output_status': int(parts[10]), + 'current_direction': "Charging" if int(parts[11]) == 0 else "Discharging", + 'battery_life': int(parts[12]) + } + +def print_data(data): + print(f"Voltage: {data['voltage']}V") + print(f"Current: {data['current']}A") + print(f"Remaining Capacity: {data['remaining_capacity']}Ah") + print(f"Cumulative Capacity: {data['cumulative_capacity']}Ah") + print(f"Watt Hours: {data['watt_hours']}kWh") + print(f"Temperature: {data['temperature']}°C") + print(f"Output Status: {data['output_status']}") + print(f"Current Direction: {data['current_direction']}") + print(f"Battery Life: {data['battery_life']} minutes") + print("---") + + +async def list_gatt_services(address): + async with BleakClient(address) as client: + print(f"Connected to {client.address}") + services = await client.get_services() + + print("\nGATT Services:") + for service in services: + print(f"Service: {service.uuid}") + for char in service.characteristics: + print(f" Characteristic: {char.uuid}") + print(f" Properties: {', '.join(char.properties)}") + for descriptor in char.descriptors: + print(f" Descriptor: {descriptor.uuid}") + +async def main(): + juntek_address = "XX:XX:XX:XX:XX:XX" # Replace with your Juntek KL140F's Bluetooth address + juntek_address = "84:C2:E4:44:59:59" + await connect_juntek(juntek_address) + await list_gatt_services(juntek_address) + +if __name__ == "__main__": + asyncio.run(main()) + diff --git a/basejun3_bt.py b/basejun3_bt.py new file mode 100644 index 0000000..5069241 --- /dev/null +++ b/basejun3_bt.py @@ -0,0 +1,76 @@ +import asyncio +from bleak import BleakClient, BleakScanner + +# JUNTEK_UUID = "0000ffe1-0000-1000-8000-00805f9b34fb" +JUNTEK_UUID = "00002a24-0000-1000-8000-00805f9b34fb" + +async def connect_juntek(address): + device = await BleakScanner.find_device_by_address(address) + if not device: + print(f"Device with address {address} not found") + return + + async with BleakClient(device) as client: + print(f"Connected to {device.name}") + + while True: + try: + data = await client.read_gatt_char(JUNTEK_UUID) + decoded_data = data.decode('utf-8') + parsed_data = parse_juntek_data(decoded_data) + print_data(parsed_data) + await asyncio.sleep(1) + except Exception as e: + print(f"Error: {e}") + break + +def parse_juntek_data(data): + parts = data.split(',') + return { + 'voltage': float(parts[2]) / 100, + 'current': float(parts[3]) / 100, + 'remaining_capacity': float(parts[4]) / 100, + 'cumulative_capacity': float(parts[5]) / 100, + 'watt_hours': float(parts[6]) / 10000, + 'temperature': float(parts[8]) - 100, + 'output_status': int(parts[10]), + 'current_direction': "Charging" if int(parts[11]) == 0 else "Discharging", + 'battery_life': int(parts[12]) + } + +def print_data(data): + print(f"Voltage: {data['voltage']}V") + print(f"Current: {data['current']}A") + print(f"Remaining Capacity: {data['remaining_capacity']}Ah") + print(f"Cumulative Capacity: {data['cumulative_capacity']}Ah") + print(f"Watt Hours: {data['watt_hours']}kWh") + print(f"Temperature: {data['temperature']}°C") + print(f"Output Status: {data['output_status']}") + print(f"Current Direction: {data['current_direction']}") + print(f"Battery Life: {data['battery_life']} minutes") + print("---") + + +async def list_gatt_services(address): + async with BleakClient(address) as client: + print(f"Connected to {client.address}") + services = await client.get_services() + + print("\nGATT Services:") + for service in services: + print(f"Service: {service.uuid}") + for char in service.characteristics: + print(f" Characteristic: {char.uuid}") + print(f" Properties: {', '.join(char.properties)}") + for descriptor in char.descriptors: + print(f" Descriptor: {descriptor.uuid}") + +async def main(): + juntek_address = "XX:XX:XX:XX:XX:XX" # Replace with your Juntek KL140F's Bluetooth address + juntek_address = "84:C2:E4:44:59:59" + await connect_juntek(juntek_address) + await list_gatt_services(juntek_address) + +if __name__ == "__main__": + asyncio.run(main()) + diff --git a/config.py b/config.py index d095380..f95bbc4 100644 --- a/config.py +++ b/config.py @@ -3,8 +3,9 @@ MQTT_USER='user' MQTT_PASS='pass' # Mac Address of the Juntec BT -JUNTEC_ADDR="XX:XX:XX:XX:XX:XX" +# JUNTEC_ADDR="XX:XX:XX:XX:XX:XX" +JUNTEC_ADDR="84:C2:E4:44:59:59" # Battery Bank Capacity in Ah -BATT_CAP=200 +BATT_CAP=100 # Port where the RS485 is located RS485 = '/dev/ttyUSB0' diff --git a/top5ble.py b/top5ble.py new file mode 100644 index 0000000..acd9b77 --- /dev/null +++ b/top5ble.py @@ -0,0 +1,23 @@ +import asyncio +from bleak import BleakScanner + +async def scan_ble_devices(): + devices = await BleakScanner.discover(timeout=5) + return sorted(devices, key=lambda d: d.rssi, reverse=True)[:50] + +def print_device_info(device): + print(f"Name: {device.name or 'Unknown'}") + print(f"Address: {device.address}") + print(f"RSSI: {device.rssi} dBm") + print("---") + +async def main(): + print("Scanning for nearby BLE devices...") + closest_devices = await scan_ble_devices() + + print("\nTop 5 closest BLE devices:") + for device in closest_devices: + print_device_info(device) + +if __name__ == "__main__": + asyncio.run(main())