meshcore 1.9.8.dev3__tar.gz → 1.9.8.dev6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/PKG-INFO +1 -1
- meshcore-1.9.8.dev6/examples/tcp_login_status.py +94 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/pyproject.toml +1 -1
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/src/meshcore/ble_cx.py +6 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/src/meshcore/commands.py +4 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/src/meshcore/events.py +11 -3
- meshcore-1.9.8.dev6/src/meshcore/lpp_json_encoder.py +56 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/src/meshcore/meshcore.py +15 -9
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/src/meshcore/reader.py +26 -8
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/src/meshcore/serial_cx.py +8 -1
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/src/meshcore/tcp_cx.py +7 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/.gitignore +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/LICENSE +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/README.md +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/ble_chat.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/ble_t1000_chan_msg.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/ble_t1000_custom_vars.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/ble_t1000_infos.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/ble_t1000_msg.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/ble_t1000_set_cv.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/mepo_mc_gps.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/pubsub_example.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/rf_packet_monitor.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/serial_battery_monitor.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/serial_chat.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/serial_contacts.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/serial_infos.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/serial_msg.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/serial_repeater_status.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/serial_repeater_telemetry.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/serial_trace.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/tcp_chat.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/tcp_mchome_contacts.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/tcp_mchome_infos.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/tcp_mchome_msg.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/examples/tcp_mchome_readmsgs.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/pytest.ini +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/src/meshcore/__init__.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/src/meshcore/packets.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/tests/README.md +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/tests/unit/test_commands.py +0 -0
- {meshcore-1.9.8.dev3 → meshcore-1.9.8.dev6}/tests/unit/test_events.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meshcore
|
|
3
|
-
Version: 1.9.8.
|
|
3
|
+
Version: 1.9.8.dev6
|
|
4
4
|
Summary: Base classes for communicating with meshcore companion radios
|
|
5
5
|
Project-URL: Homepage, https://github.com/fdlamotte/meshcore_py
|
|
6
6
|
Project-URL: Issues, https://github.com/fdlamotte/meshcore_py/issues
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import argparse
|
|
5
|
+
import logging
|
|
6
|
+
from math import log
|
|
7
|
+
|
|
8
|
+
from meshcore import MeshCore
|
|
9
|
+
from meshcore.events import EventType
|
|
10
|
+
|
|
11
|
+
# Set up logging
|
|
12
|
+
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
async def main():
|
|
16
|
+
# Parse command line arguments
|
|
17
|
+
parser = argparse.ArgumentParser(description='Get status from a repeater via TCP connection')
|
|
18
|
+
parser.add_argument('-host', '--hostname', required=True, help='TCP hostname or IP address')
|
|
19
|
+
parser.add_argument('-port', '--port', type=int, required=True, help='TCP port number')
|
|
20
|
+
parser.add_argument('-r', '--repeater', required=True, help='Repeater name')
|
|
21
|
+
parser.add_argument('-pw', '--password', required=True, help='Password for login')
|
|
22
|
+
args = parser.parse_args()
|
|
23
|
+
|
|
24
|
+
# Connect to the device
|
|
25
|
+
print(f"Connecting to TCP {args.hostname}:{args.port}...")
|
|
26
|
+
mc = await MeshCore.create_tcp(args.hostname, args.port, debug=True)
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
# Set up a simple event handler to log all events
|
|
30
|
+
async def log_event(event):
|
|
31
|
+
print(f"EVENT: {event.type.name} - Payload: {event.payload}")
|
|
32
|
+
|
|
33
|
+
# Subscribe to login events
|
|
34
|
+
mc.subscribe(EventType.LOGIN_SUCCESS, log_event)
|
|
35
|
+
mc.subscribe(EventType.LOGIN_FAILED, log_event)
|
|
36
|
+
mc.subscribe(EventType.STATUS_RESPONSE, log_event)
|
|
37
|
+
|
|
38
|
+
# Get contacts
|
|
39
|
+
await mc.ensure_contacts()
|
|
40
|
+
|
|
41
|
+
repeater = mc.get_contact_by_name(args.repeater)
|
|
42
|
+
|
|
43
|
+
if repeater is None:
|
|
44
|
+
print(f"Repeater '{args.repeater}' not found in contacts.")
|
|
45
|
+
print(f"Available contacts: {mc.contacts}")
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
print(f"Found repeater: {repeater}")
|
|
49
|
+
|
|
50
|
+
# Send login request
|
|
51
|
+
print(f"Sending login request to '{args.repeater}'...")
|
|
52
|
+
login_cmd = await mc.commands.send_login(repeater, args.password)
|
|
53
|
+
if login_cmd.type == EventType.ERROR:
|
|
54
|
+
print(f"Login failed: {login_cmd.payload}")
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
filter = {"pubkey_prefix": repeater["public_key"][0:12]}
|
|
58
|
+
login_result = await mc.wait_for_event(EventType.LOGIN_SUCCESS, filter, timeout=10)
|
|
59
|
+
print(f"Login result: {login_result}")
|
|
60
|
+
|
|
61
|
+
send_ver = await mc.commands.send_cmd(repeater, "ver")
|
|
62
|
+
if send_ver.type == EventType.ERROR:
|
|
63
|
+
print(f"Error sending version command: {send_ver.payload}")
|
|
64
|
+
return
|
|
65
|
+
await mc.wait_for_event(EventType.MESSAGES_WAITING)
|
|
66
|
+
ver_msg = await mc.commands.get_msg()
|
|
67
|
+
print(f"Version message: {ver_msg.payload}")
|
|
68
|
+
|
|
69
|
+
# Send status request
|
|
70
|
+
print("Sending status request...")
|
|
71
|
+
await mc.commands.send_statusreq(repeater)
|
|
72
|
+
|
|
73
|
+
# Wait for status response
|
|
74
|
+
print("Waiting for status response event...")
|
|
75
|
+
status_event = await mc.wait_for_event(EventType.STATUS_RESPONSE, timeout=5.0)
|
|
76
|
+
|
|
77
|
+
if status_event:
|
|
78
|
+
print(f"Status response received: {status_event.payload}")
|
|
79
|
+
else:
|
|
80
|
+
print("No status response received within timeout")
|
|
81
|
+
|
|
82
|
+
finally:
|
|
83
|
+
# Always disconnect properly
|
|
84
|
+
print("Disconnecting...")
|
|
85
|
+
await mc.disconnect()
|
|
86
|
+
print("Disconnected from device")
|
|
87
|
+
|
|
88
|
+
if __name__ == "__main__":
|
|
89
|
+
try:
|
|
90
|
+
asyncio.run(main())
|
|
91
|
+
except KeyboardInterrupt:
|
|
92
|
+
print("\nOperation cancelled by user")
|
|
93
|
+
except Exception as e:
|
|
94
|
+
print(f"Error: {e}")
|
|
@@ -91,3 +91,9 @@ class BLEConnection:
|
|
|
91
91
|
logger.error("RX characteristic not found")
|
|
92
92
|
return False
|
|
93
93
|
await self.client.write_gatt_char(self.rx_char, bytes(data), response=False)
|
|
94
|
+
|
|
95
|
+
async def disconnect(self):
|
|
96
|
+
"""Disconnect from the BLE device."""
|
|
97
|
+
if self.client and self.client.is_connected:
|
|
98
|
+
await self.client.disconnect()
|
|
99
|
+
logger.debug("BLE Connection closed")
|
|
@@ -253,6 +253,10 @@ class CommandHandler:
|
|
|
253
253
|
data = b"\x11"
|
|
254
254
|
return await self.send(data, [EventType.CONTACT_URI, EventType.ERROR])
|
|
255
255
|
|
|
256
|
+
async def import_contact(self, card_data) -> Event:
|
|
257
|
+
data = b"\x12" + card_data
|
|
258
|
+
return await self.send(data, [EventType.OK, EventType.ERROR])
|
|
259
|
+
|
|
256
260
|
async def remove_contact(self, key: DestinationType) -> Event:
|
|
257
261
|
key_bytes = _validate_destination(key, prefix_length=32)
|
|
258
262
|
logger.debug(f"Removing contact: {key_bytes.hex()}")
|
|
@@ -64,6 +64,15 @@ class Event:
|
|
|
64
64
|
# Add any keyword arguments to the attributes dictionary
|
|
65
65
|
if kwargs:
|
|
66
66
|
self.attributes.update(kwargs)
|
|
67
|
+
def clone(self):
|
|
68
|
+
"""
|
|
69
|
+
Create a copy of the event.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
A new Event object with the same type, payload, and attributes.
|
|
73
|
+
"""
|
|
74
|
+
copied_payload = self.payload.copy() if isinstance(self.payload, dict) else self.payload
|
|
75
|
+
return Event(self.type, copied_payload, self.attributes.copy())
|
|
67
76
|
|
|
68
77
|
|
|
69
78
|
class Subscription:
|
|
@@ -79,7 +88,7 @@ class Subscription:
|
|
|
79
88
|
|
|
80
89
|
class EventDispatcher:
|
|
81
90
|
def __init__(self):
|
|
82
|
-
self.queue = asyncio.Queue()
|
|
91
|
+
self.queue: asyncio.Queue[Event] = asyncio.Queue()
|
|
83
92
|
self.subscriptions: List[Subscription] = []
|
|
84
93
|
self.running = False
|
|
85
94
|
self._task = None
|
|
@@ -118,7 +127,6 @@ class EventDispatcher:
|
|
|
118
127
|
event = await self.queue.get()
|
|
119
128
|
logger.debug(f"Dispatching event: {event.type}, {event.payload}, {event.attributes}")
|
|
120
129
|
for subscription in self.subscriptions.copy():
|
|
121
|
-
logger.debug(f"Checking subscription: {subscription.event_type}, {subscription.attribute_filters}")
|
|
122
130
|
# Check if event type matches
|
|
123
131
|
if subscription.event_type is None or subscription.event_type == event.type:
|
|
124
132
|
# Check if all attribute filters match
|
|
@@ -128,7 +136,7 @@ class EventDispatcher:
|
|
|
128
136
|
for key, value in subscription.attribute_filters.items()):
|
|
129
137
|
continue
|
|
130
138
|
try:
|
|
131
|
-
result = subscription.callback(event)
|
|
139
|
+
result = subscription.callback(event.clone())
|
|
132
140
|
if asyncio.iscoroutine(result):
|
|
133
141
|
await result
|
|
134
142
|
except Exception as e:
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from cayennelpp import LppFrame, LppData
|
|
2
|
+
from cayennelpp.lpp_type import LppType
|
|
3
|
+
|
|
4
|
+
# type name "how to display vale"
|
|
5
|
+
# display : None: (use lib default), []: only one value to display, ["field1", "field2" ...]: meaning of each field
|
|
6
|
+
my_lpp_types = {
|
|
7
|
+
0: ('digital input', []),
|
|
8
|
+
1: ('digital output', []),
|
|
9
|
+
2: ('analog input', []),
|
|
10
|
+
3: ('analog output', []),
|
|
11
|
+
100: ('generic sensor', []),
|
|
12
|
+
101: ('illuminance', []),
|
|
13
|
+
102: ('presence', []),
|
|
14
|
+
103: ('temperature', []),
|
|
15
|
+
104: ('humidity', []),
|
|
16
|
+
113: ('accelerometer', ["acc_x", "acc_y", "acc_z"]),
|
|
17
|
+
115: ('barometer', []),
|
|
18
|
+
116: ('voltage', []),
|
|
19
|
+
117: ('current', []),
|
|
20
|
+
118: ('frequency', []),
|
|
21
|
+
120: ('percentage', []),
|
|
22
|
+
121: ('altitude', []),
|
|
23
|
+
122: ('load', []),
|
|
24
|
+
125: ('concentration', []),
|
|
25
|
+
128: ('power', []),
|
|
26
|
+
130: ('distance', []),
|
|
27
|
+
131: ('energy', []),
|
|
28
|
+
132: ('direction', None),
|
|
29
|
+
133: ('time', []),
|
|
30
|
+
134: ('gyrometer', None),
|
|
31
|
+
135: ('colour', ["red", "green", "blue"]),
|
|
32
|
+
136: ('gps', ["latitude", "longitude", "altitude"]),
|
|
33
|
+
142: ('switch', []),
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
def lpp_json_encoder (obj) :
|
|
37
|
+
"""Encode LppType, LppData, and LppFrame to JSON."""
|
|
38
|
+
if isinstance(obj, LppFrame):
|
|
39
|
+
return obj.data
|
|
40
|
+
if isinstance(obj, LppType):
|
|
41
|
+
return my_lpp_types[obj.type][0]
|
|
42
|
+
if isinstance(obj, LppData):
|
|
43
|
+
d = {"channel" : obj.channel, "type" : obj.type}
|
|
44
|
+
if my_lpp_types[obj.type.type][1] is None :
|
|
45
|
+
d["value"] = obj.value
|
|
46
|
+
elif len(my_lpp_types[obj.type.type][1]) == 0 :
|
|
47
|
+
d["value"] = obj.value[0]
|
|
48
|
+
else :
|
|
49
|
+
val_dict = {}
|
|
50
|
+
i = 0
|
|
51
|
+
for t in my_lpp_types[obj.type.type][1] :
|
|
52
|
+
val_dict[t] = obj.value[i]
|
|
53
|
+
i = i + 1
|
|
54
|
+
d["value"] = val_dict
|
|
55
|
+
return d
|
|
56
|
+
raise TypeError(repr(obj) + " is not JSON serialized")
|
|
@@ -5,7 +5,9 @@ from typing import Optional, Dict, Any, Union
|
|
|
5
5
|
from .events import EventDispatcher, EventType
|
|
6
6
|
from .reader import MessageReader
|
|
7
7
|
from .commands import CommandHandler
|
|
8
|
-
|
|
8
|
+
from .ble_cx import BLEConnection
|
|
9
|
+
from .tcp_cx import TCPConnection
|
|
10
|
+
from .serial_cx import SerialConnection
|
|
9
11
|
|
|
10
12
|
# Setup default logger
|
|
11
13
|
logger = logging.getLogger("meshcore")
|
|
@@ -45,9 +47,7 @@ class MeshCore:
|
|
|
45
47
|
|
|
46
48
|
@classmethod
|
|
47
49
|
async def create_tcp(cls, host: str, port: int, debug: bool = False, default_timeout=None) -> 'MeshCore':
|
|
48
|
-
"""Create and connect a MeshCore instance using TCP connection"""
|
|
49
|
-
from .tcp_cx import TCPConnection
|
|
50
|
-
|
|
50
|
+
"""Create and connect a MeshCore instance using TCP connection"""
|
|
51
51
|
connection = TCPConnection(host, port)
|
|
52
52
|
await connection.connect()
|
|
53
53
|
|
|
@@ -58,9 +58,6 @@ class MeshCore:
|
|
|
58
58
|
@classmethod
|
|
59
59
|
async def create_serial(cls, port: str, baudrate: int = 115200, debug: bool = False, default_timeout=None) -> 'MeshCore':
|
|
60
60
|
"""Create and connect a MeshCore instance using serial connection"""
|
|
61
|
-
from .serial_cx import SerialConnection
|
|
62
|
-
import asyncio
|
|
63
|
-
|
|
64
61
|
connection = SerialConnection(port, baudrate)
|
|
65
62
|
await connection.connect()
|
|
66
63
|
await asyncio.sleep(0.1) # Time for transport to establish
|
|
@@ -75,7 +72,6 @@ class MeshCore:
|
|
|
75
72
|
|
|
76
73
|
If address is None, it will scan for and connect to the first available MeshCore device.
|
|
77
74
|
"""
|
|
78
|
-
from .ble_cx import BLEConnection
|
|
79
75
|
|
|
80
76
|
connection = BLEConnection(address)
|
|
81
77
|
result = await connection.connect()
|
|
@@ -91,7 +87,17 @@ class MeshCore:
|
|
|
91
87
|
return await self.commands.send_appstart()
|
|
92
88
|
|
|
93
89
|
async def disconnect(self):
|
|
90
|
+
"""Disconnect from the device and clean up resources."""
|
|
91
|
+
# First stop the dispatcher to prevent any new events
|
|
94
92
|
await self.dispatcher.stop()
|
|
93
|
+
|
|
94
|
+
# Stop auto message fetching if it's running
|
|
95
|
+
if hasattr(self, '_auto_fetch_subscription') and self._auto_fetch_subscription:
|
|
96
|
+
await self.stop_auto_message_fetching()
|
|
97
|
+
|
|
98
|
+
# Disconnect the connection object
|
|
99
|
+
if self.cx:
|
|
100
|
+
await self.cx.disconnect()
|
|
95
101
|
|
|
96
102
|
def stop(self):
|
|
97
103
|
"""Synchronously stop the event dispatcher task"""
|
|
@@ -99,7 +105,7 @@ class MeshCore:
|
|
|
99
105
|
self.dispatcher.running = False
|
|
100
106
|
self.dispatcher._task.cancel()
|
|
101
107
|
|
|
102
|
-
def subscribe(self, event_type: EventType, callback, attribute_filters: Optional[Dict[str, Any]] = None):
|
|
108
|
+
def subscribe(self, event_type: Union[EventType, None], callback, attribute_filters: Optional[Dict[str, Any]] = None):
|
|
103
109
|
"""
|
|
104
110
|
Subscribe to events using EventType enum with optional attribute filtering
|
|
105
111
|
|
|
@@ -2,10 +2,11 @@ import sys
|
|
|
2
2
|
import logging
|
|
3
3
|
import asyncio
|
|
4
4
|
import json
|
|
5
|
-
from cayennelpp import LppFrame, LppData
|
|
5
|
+
from cayennelpp import LppFrame, LppData
|
|
6
6
|
from typing import Any, Optional, Dict
|
|
7
7
|
from .events import Event, EventType, EventDispatcher
|
|
8
8
|
from .packets import PacketType
|
|
9
|
+
from meshcore.lpp_json_encoder import lpp_json_encoder
|
|
9
10
|
|
|
10
11
|
logger = logging.getLogger("meshcore")
|
|
11
12
|
|
|
@@ -256,14 +257,31 @@ class MessageReader:
|
|
|
256
257
|
await self.dispatcher.dispatch(Event(EventType.RAW_DATA, res))
|
|
257
258
|
|
|
258
259
|
elif packet_type_value == PacketType.LOGIN_SUCCESS.value:
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
260
|
+
res = {}
|
|
261
|
+
if len(data) > 1:
|
|
262
|
+
res["permissions"] = data[1]
|
|
263
|
+
res["is_admin"] = (data[1] & 1) == 1 # Check if admin bit is set
|
|
264
|
+
|
|
265
|
+
if len(data) > 7:
|
|
266
|
+
res["pubkey_prefix"] = data[2:8].hex()
|
|
267
|
+
|
|
268
|
+
attributes = {
|
|
269
|
+
"pubkey_prefix": res.get("pubkey_prefix")
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
await self.dispatcher.dispatch(Event(EventType.LOGIN_SUCCESS, res, attributes))
|
|
262
273
|
|
|
263
274
|
elif packet_type_value == PacketType.LOGIN_FAILED.value:
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
275
|
+
res = {}
|
|
276
|
+
|
|
277
|
+
if len(data) > 7:
|
|
278
|
+
res["pubkey_prefix"] = data[2:8].hex()
|
|
279
|
+
|
|
280
|
+
attributes = {
|
|
281
|
+
"pubkey_prefix": res.get("pubkey_prefix")
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
await self.dispatcher.dispatch(Event(EventType.LOGIN_FAILED, res, attributes))
|
|
267
285
|
|
|
268
286
|
elif packet_type_value == PacketType.STATUS_RESPONSE.value:
|
|
269
287
|
res = {}
|
|
@@ -391,7 +409,7 @@ class MessageReader:
|
|
|
391
409
|
data.append(lppdata)
|
|
392
410
|
i = i + len(lppdata)
|
|
393
411
|
|
|
394
|
-
lpp = json.loads(json.dumps(LppFrame(data), default=
|
|
412
|
+
lpp = json.loads(json.dumps(LppFrame(data), default=lpp_json_encoder))
|
|
395
413
|
|
|
396
414
|
res["lpp"] = lpp
|
|
397
415
|
|
|
@@ -86,4 +86,11 @@ class SerialConnection:
|
|
|
86
86
|
size = len(data)
|
|
87
87
|
pkt = b"\x3c" + size.to_bytes(2, byteorder="little") + data
|
|
88
88
|
logger.debug(f"sending pkt : {pkt}")
|
|
89
|
-
self.transport.write(pkt)
|
|
89
|
+
self.transport.write(pkt)
|
|
90
|
+
|
|
91
|
+
async def disconnect(self):
|
|
92
|
+
"""Close the serial connection."""
|
|
93
|
+
if self.transport:
|
|
94
|
+
self.transport.close()
|
|
95
|
+
self.transport = None
|
|
96
|
+
logger.debug("Serial Connection closed")
|
|
@@ -85,3 +85,10 @@ class TCPConnection:
|
|
|
85
85
|
pkt = b"\x3c" + size.to_bytes(2, byteorder="little") + data
|
|
86
86
|
logger.debug(f"sending pkt : {pkt}")
|
|
87
87
|
self.transport.write(pkt)
|
|
88
|
+
|
|
89
|
+
async def disconnect(self):
|
|
90
|
+
"""Close the TCP connection."""
|
|
91
|
+
if self.transport:
|
|
92
|
+
self.transport.close()
|
|
93
|
+
self.transport = None
|
|
94
|
+
logger.debug("TCP Connection closed")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|