Feature/v0.2.0 (#7)
* heateroutput limit 0 - 15000 w * heatoutput always positive * ENUM_IN_FSV_2041 value 0c00 unknwon added * recalculate crc6 checksum and check it * skip exception to reduce logging * NASAPacket and NASAMessage prepared for write mode MQTT Auto Discovery changed single entitity to all entities NASA Packet crc16 Checksum verificated * - Changed MQTT Auto Discovery Config Message from single Entitiy to all Entities at ones, known devices are fully configured, not known empty (markt to delete) - NASAPacket and NASAMessage are now bidirectional, can decode and encode Packets - Added crc16 Checksum check for any Packet to reduce incorrect value changes - Folling warnings moved to SkipInvalidPacketException and from warning to debug log level to reduce Logentries - Source Adress Class out of enum - Destination Adress Class out of enum - Checksum for package could not be validatet calculated - Message with structure type must have capacity of 1. * NASA_OUTDOOR_HP as kw unit * NASA Repository, measurements enums completed * filter wifikit heartbeat * process only packets from indoor or outdoor * correct readme * remove expire * device discovery status * new mqtt hass configuration approach * added new measurements * added new logging features from config * NASA_EHSSENTINEL_TOTAL_COP added * removed silentMode, added logging proccessedMessage * loaded devices * loaded devices counter fix * only if retain true * final 0.2.0 commit
This commit is contained in:
@@ -5,7 +5,7 @@ import traceback
|
||||
from MessageProcessor import MessageProcessor
|
||||
from EHSArguments import EHSArguments
|
||||
from EHSConfig import EHSConfig
|
||||
from EHSExceptions import MessageWarningException, MessageCapacityStructureWarning
|
||||
from EHSExceptions import MessageWarningException, SkipInvalidPacketException
|
||||
from MQTTClient import MQTTClient
|
||||
import aiofiles
|
||||
import json
|
||||
@@ -13,10 +13,11 @@ import struct
|
||||
import binascii
|
||||
|
||||
# Get the logger
|
||||
from CustomLogger import logger, setSilent
|
||||
from NASAPacket import NASAPacket
|
||||
from CustomLogger import logger
|
||||
from NASAPacket import NASAPacket, AddressClassEnum, PacketType, DataType
|
||||
from NASAMessage import NASAMessage
|
||||
|
||||
version = "0.1.0 Stable"
|
||||
version = "0.2.0 Stable"
|
||||
|
||||
async def main():
|
||||
"""
|
||||
@@ -26,9 +27,8 @@ async def main():
|
||||
2. Reads command-line arguments.
|
||||
3. Reads configuration settings.
|
||||
4. Connects to the MQTT broker.
|
||||
5. Sets silent mode if specified in the configuration.
|
||||
6. If dry run mode is enabled, reads data from a dump file and processes it.
|
||||
7. If not in dry run mode, reads data from a serial port and processes it.
|
||||
5. If dry run mode is enabled, reads data from a dump file and processes it.
|
||||
6. If not in dry run mode, reads data from a serial port and processes it.
|
||||
Args:
|
||||
None
|
||||
Returns:
|
||||
@@ -61,10 +61,6 @@ async def main():
|
||||
|
||||
await asyncio.sleep(1)
|
||||
|
||||
# if Silent is true, set Silent Mode
|
||||
if config.GENERAL['silentMode']:
|
||||
setSilent()
|
||||
|
||||
# if dryrun then we read from dumpfile
|
||||
if args.DRYRUN:
|
||||
logger.info(f"DRYRUN detected, reading from dumpfile {args.DUMPFILE}")
|
||||
@@ -75,12 +71,12 @@ async def main():
|
||||
except:
|
||||
line = line.strip().replace("'", "").replace("[", "").replace("]", "").split(", ") # for ['0x1', '0x2' ..]
|
||||
line = [int(value, 16) for value in line]
|
||||
await process_packet(line, args)
|
||||
await process_packet(line, args, config)
|
||||
else:
|
||||
# we are not in dryrun mode, so we need to read from Serial Pimort
|
||||
await serial_read(config, args)
|
||||
await serial_connection(config, args)
|
||||
|
||||
async def process_buffer(buffer, args):
|
||||
async def process_buffer(buffer, args, config):
|
||||
"""
|
||||
Processes a buffer of data asynchronously, identifying and handling packets based on specific criteria.
|
||||
Args:
|
||||
@@ -108,14 +104,14 @@ async def process_buffer(buffer, args):
|
||||
for i in range(0, len(buffer)):
|
||||
if buffer[i] == 0x32:
|
||||
if (len(buffer[i:]) > 14):
|
||||
asyncio.create_task(process_packet(buffer[i:], args))
|
||||
asyncio.create_task(process_packet(buffer[i:], args, config))
|
||||
else:
|
||||
logger.debug(f"Buffermessages to short for NASA {len(buffer)}")
|
||||
break
|
||||
else:
|
||||
logger.debug(f"Buffer to short for NASA {len(buffer)}")
|
||||
|
||||
async def serial_read(config, args):
|
||||
async def serial_connection(config, args):
|
||||
"""
|
||||
Asynchronously reads data from a serial connection and processes it.
|
||||
Args:
|
||||
@@ -147,25 +143,28 @@ async def serial_read(config, args):
|
||||
stopbits=serial.STOPBITS_ONE,
|
||||
bytesize=serial.EIGHTBITS,
|
||||
rtscts=True,
|
||||
timeout=0
|
||||
timeout=1
|
||||
)
|
||||
|
||||
# start the async buffer process
|
||||
#asyncio.create_task(process_buffer(buffer, args))# start the async buffer process
|
||||
|
||||
# TODO have to be tested and verified, please do not try it yet
|
||||
# start the async writer process
|
||||
#asyncio.create_task(serial_write(writer, reader))
|
||||
await asyncio.gather(
|
||||
serial_read(reader, args, config),
|
||||
#serial_write(writer, reader, args),
|
||||
)
|
||||
|
||||
# Read loop
|
||||
|
||||
async def serial_read(reader, args, config):
|
||||
while True:
|
||||
data = await reader.readuntil(b'\x34') # Read up to end of next message 0x34
|
||||
if data:
|
||||
asyncio.create_task(process_buffer(data, args))
|
||||
asyncio.create_task(process_buffer(data, args, config))
|
||||
#buffer.extend(data)
|
||||
logger.debug(f"Received: {data}")
|
||||
logger.debug(f"Received: {data!r}")
|
||||
logger.debug(f"Received: {[hex(x) for x in data]}")
|
||||
|
||||
async def serial_write(writer, reader):
|
||||
await asyncio.sleep(0.1) # Yield control to other tasks
|
||||
|
||||
async def serial_write(writer:asyncio.StreamWriter, reader: asyncio.StreamReader, args):
|
||||
"""
|
||||
|
||||
TODO Not used yet, only for future use...
|
||||
@@ -183,36 +182,85 @@ async def serial_write(writer, reader):
|
||||
await asyncio.sleep(5)
|
||||
# Example data to write
|
||||
|
||||
packet = bytearray([
|
||||
#0x32, # Packet Start Byte
|
||||
#0x00, 0x12, # Packet Size
|
||||
0x80, # Source Address Class JIGTester
|
||||
0xFF, # Source Channel
|
||||
0x00, # Source Address
|
||||
0x20, # Destination Address Class Indoor
|
||||
0x00, # Destination Channel
|
||||
0x00, # Destination Address
|
||||
0xC0, # Packet Information + Protocol Version + Retry Count
|
||||
0x11, # Packet Type [Normal = 1] + Data Type [Read = 1]
|
||||
0xF0, # Packet Number
|
||||
0x01, # Capacity (Number of Messages)
|
||||
0x42, 0x56, # NASA Message Number
|
||||
0x00, 0x00 # Message Payload (placeholder for return value)
|
||||
])
|
||||
|
||||
crc=binascii.crc_hqx(packet, 0)
|
||||
# NOTE: include length of CRC(2) and length of length field(2) in the
|
||||
# total length, exclude SF/TF of total length
|
||||
final_packet = struct.pack(">BH", 0x32, len(packet)+2+2) + packet + struct.pack(">HB", crc, 0x34)
|
||||
# ['0x32', '0x0', '0x12', '0x80', '0xff', '0x0', '0x20', '0x0', '0x0', '0xc0', '0x11', '0xf0', '0x1', '0x42', '0x56', '0x0', '0x0', '0xf9', '0x65', '0x34']
|
||||
# ['0x32', '0x0', '0x12', '0x80', '0xff', '0x0', '0x20', '0x0', '0x0', '0xc0', '0x11', '0xf0', '0x1', '0x42', '0x56', '0x0', '0x0', '0x38', '0xc6', '0x34']
|
||||
decoded_nasa = NASAPacket()
|
||||
decoded_nasa.set_packet_source_address_class(AddressClassEnum.WiFiKit)
|
||||
decoded_nasa.set_packet_source_channel(0)
|
||||
decoded_nasa.set_packet_source_address(144)
|
||||
decoded_nasa.set_packet_dest_address_class(AddressClassEnum.BroadcastSetLayer)
|
||||
decoded_nasa.set_packet_dest_channel(0)
|
||||
decoded_nasa.set_packet_dest_address(32)
|
||||
decoded_nasa.set_packet_information(True)
|
||||
decoded_nasa.set_packet_version(2)
|
||||
decoded_nasa.set_packet_retry_count(0)
|
||||
decoded_nasa.set_packet_type(PacketType.Normal)
|
||||
decoded_nasa.set_packet_data_type(DataType.Read)
|
||||
decoded_nasa.set_packet_number(3)
|
||||
lst = []
|
||||
tmp_msg = NASAMessage()
|
||||
tmp_msg.set_packet_message(0x4093)
|
||||
tmp_msg.set_packet_message_type(0)
|
||||
tmp_msg.set_packet_payload([0])
|
||||
lst.append(tmp_msg)
|
||||
tmp_msg = NASAMessage()
|
||||
tmp_msg.set_packet_message(0x4094)
|
||||
tmp_msg.set_packet_message_type(0)
|
||||
tmp_msg.set_packet_payload([0])
|
||||
lst.append(tmp_msg)
|
||||
tmp_msg = NASAMessage()
|
||||
tmp_msg.set_packet_message(0x4273)
|
||||
tmp_msg.set_packet_message_type(1)
|
||||
tmp_msg.set_packet_payload([0, 0])
|
||||
lst.append(tmp_msg)
|
||||
tmp_msg = NASAMessage()
|
||||
tmp_msg.set_packet_message(0x4274)
|
||||
tmp_msg.set_packet_message_type(1)
|
||||
tmp_msg.set_packet_payload([0, 0])
|
||||
lst.append(tmp_msg)
|
||||
tmp_msg = NASAMessage()
|
||||
tmp_msg.set_packet_message(0x4275)
|
||||
tmp_msg.set_packet_message_type(1)
|
||||
tmp_msg.set_packet_payload([0, 0])
|
||||
lst.append(tmp_msg)
|
||||
tmp_msg = NASAMessage()
|
||||
tmp_msg.set_packet_message(0x4276)
|
||||
tmp_msg.set_packet_message_type(1)
|
||||
tmp_msg.set_packet_payload([0, 0])
|
||||
lst.append(tmp_msg)
|
||||
tmp_msg = NASAMessage()
|
||||
tmp_msg.set_packet_message(0x4277)
|
||||
tmp_msg.set_packet_message_type(1)
|
||||
tmp_msg.set_packet_payload([0, 0])
|
||||
lst.append(tmp_msg)
|
||||
tmp_msg = NASAMessage()
|
||||
tmp_msg.set_packet_message(0x4278)
|
||||
tmp_msg.set_packet_message_type(1)
|
||||
tmp_msg.set_packet_payload([0, 0])
|
||||
lst.append(tmp_msg)
|
||||
tmp_msg = NASAMessage()
|
||||
tmp_msg.set_packet_message(0x4279)
|
||||
tmp_msg.set_packet_message_type(1)
|
||||
tmp_msg.set_packet_payload([0, 0])
|
||||
lst.append(tmp_msg)
|
||||
tmp_msg = NASAMessage()
|
||||
tmp_msg.set_packet_message(0x427a)
|
||||
tmp_msg.set_packet_message_type(1)
|
||||
tmp_msg.set_packet_payload([0, 0])
|
||||
lst.append(tmp_msg)
|
||||
tmp_msg = NASAMessage()
|
||||
tmp_msg.set_packet_message(0x427b)
|
||||
tmp_msg.set_packet_message_type(1)
|
||||
tmp_msg.set_packet_payload([0, 0])
|
||||
lst.append(tmp_msg)
|
||||
decoded_nasa.set_packet_messages(lst)
|
||||
final_packet = decoded_nasa.to_raw()
|
||||
writer.write(final_packet)
|
||||
await writer.drain()
|
||||
logger.debug(f"Sent data raw: {final_packet}")
|
||||
logger.debug(f"Sent data raw: {[hex(x) for x in final_packet]}")
|
||||
await asyncio.sleep(1) # Adjust the interval as needed
|
||||
logger.info(f"Sent data raw: {final_packet}")
|
||||
logger.info(f"Sent data raw: {decoded_nasa}")
|
||||
logger.info(f"Sent data raw: {[hex(x) for x in final_packet]}")
|
||||
logger.info(f"Sent data raw: {[x for x in final_packet]}")
|
||||
|
||||
async def process_packet(buffer, args):
|
||||
async def process_packet(buffer, args, config):
|
||||
"""
|
||||
Asynchronously processes a packet buffer.
|
||||
If `dumpWriter` is `None`, it attempts to process the packet using `MessageProcessor`.
|
||||
@@ -233,13 +281,29 @@ async def process_packet(buffer, args):
|
||||
logger.debug("Packet processed: ")
|
||||
logger.debug(f"Packet raw: {[hex(x) for x in buffer]}")
|
||||
logger.debug(nasa_packet)
|
||||
messageProcessor = MessageProcessor()
|
||||
messageProcessor.process_message(nasa_packet)
|
||||
if nasa_packet.packet_source_address_class in (AddressClassEnum.Outdoor, AddressClassEnum.Indoor):
|
||||
messageProcessor = MessageProcessor()
|
||||
messageProcessor.process_message(nasa_packet)
|
||||
elif nasa_packet.packet_source_address_class == AddressClassEnum.WiFiKit and \
|
||||
nasa_packet.packet_dest_address_class == AddressClassEnum.BroadcastSelfLayer and \
|
||||
nasa_packet.packet_data_type == DataType.Notification:
|
||||
pass
|
||||
else:
|
||||
if config.LOGGING['packetNotFromIndoorOutdoor']:
|
||||
logger.info("Message not From Indoor or Outdoor")
|
||||
logger.info(nasa_packet)
|
||||
logger.info(f"Packet int: {[x for x in buffer]}")
|
||||
logger.info(f"Packet hex: {[hex(x) for x in buffer]}")
|
||||
else:
|
||||
logger.debug("Message not From Indoor or Outdoor")
|
||||
logger.debug(nasa_packet)
|
||||
logger.debug(f"Packet int: {[x for x in buffer]}")
|
||||
logger.debug(f"Packet hex: {[hex(x) for x in buffer]}")
|
||||
except ValueError as e:
|
||||
logger.warning("Value Error on parsing Packet, Packet will be skipped")
|
||||
logger.warning(f"Error processing message: {e}")
|
||||
logger.warning(f"Complete Packet: {[hex(x) for x in buffer]}")
|
||||
except MessageCapacityStructureWarning as e:
|
||||
except SkipInvalidPacketException as e:
|
||||
logger.debug("Warnung accured, Packet will be skipped")
|
||||
logger.debug(f"Error processing message: {e}")
|
||||
logger.debug(f"Complete Packet: {[hex(x) for x in buffer]}")
|
||||
|
||||
Reference in New Issue
Block a user