Feature/initial (#1)

* initial commit
* systemd service implementation
This commit is contained in:
echoDaveD
2025-02-11 20:47:47 +01:00
committed by GitHub
parent 90b74d1b51
commit b2cd11f129
20 changed files with 9317 additions and 1 deletions

4
.gitignore vendored
View File

@@ -169,3 +169,7 @@ cython_debug/
# PyPI configuration file
.pypirc
/config.yml
prot.csv
helpertils/serial.py
helpertils/test.py

105
CustomLogger.py Normal file
View File

@@ -0,0 +1,105 @@
import logging
import inspect
class IndentFormatter(logging.Formatter):
"""
A custom logging formatter that adds indentation based on the call stack depth
and includes the function name in the log record.
Attributes:
baseline (int): The baseline stack depth when the formatter is initialized.
Methods:
__init__(fmt=None, datefmt=None):
Initializes the IndentFormatter with optional format and date format.
format(rec):
Formats the specified record as text, adding indentation and function name.
"""
grey = "\x1b[38;20m"
yellow = "\x1b[33;20m"
red = "\x1b[31;20m"
bold_red = "\x1b[31;1m"
reset = "\x1b[0m"
format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)"
FORMATS = {
logging.DEBUG: grey + format + reset,
logging.INFO: grey + format + reset,
logging.WARNING: yellow + format + reset,
logging.ERROR: red + format + reset,
logging.CRITICAL: bold_red + format + reset
}
def __init__( self, fmt=None, datefmt=None ):
"""
Initializes the CustomLogger instance.
Args:
fmt (str, optional): The format string for the log messages. Defaults to None.
datefmt (str, optional): The format string for the date in log messages. Defaults to None.
Attributes:
baseline (int): The baseline stack depth when the logger is initialized.
"""
logging.Formatter.__init__(self, fmt, datefmt)
self.baseline = len(inspect.stack())
def format( self, rec ):
"""
Formats the log record by adding indentation and function name.
This method customizes the log record by adding an indentation level
based on the current stack depth and includes the name of the function
from which the log call was made. It then uses the base Formatter class
to format the record and returns the formatted string.
Args:
rec (logging.LogRecord): The log record to be formatted.
Returns:
str: The formatted log record string.
"""
log_fmt = self.FORMATS.get(rec.levelno)
formatter = logging.Formatter(log_fmt)
stack = inspect.stack()
rec.indent = ' '*(len(stack)-self.baseline-3)
rec.function = stack[8][3]
out = logging.Formatter.format(self, rec)
del rec.indent; del rec.function
return out
class MessageProcessorFilter(logging.Filter):
def filter(self, record):
# Suppress INFO level messages from MessageProcessor.py
if record.levelno == logging.INFO and record.pathname.endswith("MessageProcessor.py"):
return False
return True
# The following code sets up a custom logger with indentation support.
# It creates a custom formatter, a logger instance, and a stream handler.
# The custom formatter is set to the handler, which is then added to the logger.
# Finally, the logging level is set to INFO.
formatter = IndentFormatter("%(asctime)s - (%(filename)30s:%(lineno)-3d) - [%(levelname)-7s]: %(indent)s%(message)s ")
logger = logging.getLogger('logger')
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
def setDebugMode():
"""
Set the logging level to DEBUG and log a message indicating that debug mode is enabled.
This function sets the logging level of the logger to DEBUG, which means that all messages
at the DEBUG level and above will be logged. It also logs a debug message to indicate that
debug mode has been activated.
"""
logger.setLevel(logging.DEBUG)
logger.debug("Debug mode is on...")
def setSilent():
"""
Sets the logger to silent mode, where only messages at the ERROR level or higher are displayed.
If the current logging level is not 'DEBUG', this function will log an informational message
indicating that silent mode is being activated and then set the logging level to ERROR.
"""
if logger.level != logging.DEBUG:
logger.info("Silent Mode is turning on, only Messages at Level ERROR or higher are displayed")
#logger.setLevel(logging.ERROR)
# Add the filter to suppress INFO level messages from MessageProcessor.py
logger.addFilter(MessageProcessorFilter())

89
EHSArguments.py Normal file
View File

@@ -0,0 +1,89 @@
import argparse
import os
from EHSExceptions import ArgumentException
from CustomLogger import logger, setDebugMode
class EHSArguments:
"""
EHSArguments is a singleton class that handles command-line arguments for the EHS Sentinel script.
Attributes:
CONFIGFILE (str): Path to the configuration file.
DRYRUN (bool): Flag indicating if the script should run in dry run mode.
DUMPFILE (str): Path to the dump file.
_instance (EHSArguments): Singleton instance of the class.
Methods:
__new__(cls, *args, **kwargs): Ensures only one instance of the class is created.
__init__(self): Initializes the class, parses command-line arguments, and sets attributes.
"""
CONFIGFILE = ''
DRYRUN = False
DUMPFILE = ''
_instance = None
def __new__(cls, *args, **kwargs):
"""
Create and return a new instance of the class, ensuring that only one instance exists (singleton pattern).
This method overrides the default behavior of object creation to implement the singleton pattern.
It checks if an instance of the class already exists; if not, it creates a new instance and marks it as uninitialized.
Args:
*args: Variable length argument list.
**kwargs: Arbitrary keyword arguments.
Returns:
EHSArguments: The singleton instance of the EHSArguments class.
"""
if not cls._instance:
cls._instance = super(EHSArguments, cls).__new__(cls, *args, **kwargs)
cls._instance._initialized = False
return cls._instance
def __init__(self):
"""
Initializes the EHSArguments class, parses command-line arguments, and sets up configuration.
This method performs the following steps:
1. Checks if the class has already been initialized to prevent re-initialization.
2. Sets up an argument parser to handle command-line arguments.
3. Parses the command-line arguments and validates them.
4. Checks if the specified config file and dump file exist.
5. Sets the class attributes based on the parsed arguments.
Raises:
ArgumentException: If the required arguments are not provided or if the specified files do not exist.
"""
if self._initialized:
return
self._initialized = True
logger.debug("init EHSArguments")
parser = argparse.ArgumentParser(description="Process some integers.")
parser.add_argument('--configfile', type=str, required=True, help='Config file path')
parser.add_argument('--dumpfile', type=str, required=False, help='File Path for where the Dumpfile should be written to or read from if dryrun flag is set too.')
parser.add_argument('--dryrun', action='store_true', default=False, required=False, help='Run the script in dry run mode, data will be read from DumpFile and not MQTT Message will be sent.')
parser.add_argument('--clean-known-devices', action='store_true', default=False, required=False, help='Cleans the know Devices Topic on Startup.')
parser.add_argument('-v', '--verbose', action='store_true', default=False, required=False, help='Enable verbose mode')
args = parser.parse_args()
if args.verbose:
setDebugMode()
logger.debug(args)
if args.dryrun:
if args.dumpfile is None:
raise ArgumentException(argument="--dumpfile")
else:
if not os.path.isfile(args.dumpfile):
raise ArgumentException(argument=args.dumpfile, message="Dump File does not exist")
# Check if the config file exists
if not os.path.isfile(args.configfile):
raise ArgumentException(argument=args.configfile, message="Config File does not exist")
self.CONFIGFILE = args.configfile
self.DUMPFILE = args.dumpfile
self.DRYRUN = args.dryrun
self.CLEAN_KNOWN_DEVICES = args.clean_known_devices

135
EHSConfig.py Normal file
View File

@@ -0,0 +1,135 @@
from EHSExceptions import ConfigException
from EHSArguments import EHSArguments
import yaml
import os
from CustomLogger import logger
class EHSConfig():
"""
Singleton class to handle the configuration for the EHS Sentinel application.
This class reads configuration parameters from a YAML file and validates them.
It ensures that only one instance of the configuration exists throughout the application.
Attributes:
MQTT (dict): Configuration parameters for MQTT.
GENERAL (dict): General configuration parameters.
SERIAL (dict): Configuration parameters for serial communication.
NASA_REPO (dict): Configuration parameters for NASA repository.
Methods:
__new__(cls, *args, **kwargs): Ensures only one instance of the class is created.
__init__(self, *args, **kwargs): Initializes the configuration by reading and validating the YAML file.
validate(self): Validates the configuration parameters.
"""
_instance = None
MQTT = None
GENERAL = None
SERIAL = None
NASA_REPO = None
def __new__(cls, *args, **kwargs):
"""
Create a new instance of the EHSConfig class if one does not already exist.
This method ensures that only one instance of the EHSConfig class is created
(singleton pattern). If an instance already exists, it returns the existing instance.
Args:
cls: The class being instantiated.
*args: Variable length argument list.
**kwargs: Arbitrary keyword arguments.
Returns:
EHSConfig: The single instance of the EHSConfig class.
"""
if not cls._instance:
cls._instance = super(EHSConfig, cls).__new__(cls, *args, **kwargs)
cls._instance._initialized = False
return cls._instance
def __init__(self, *args, **kwargs):
"""
Initialize the EHSConfig instance.
This method initializes the EHSConfig instance by loading configuration
settings from a YAML file specified in the EHSArguments. It ensures that
the initialization process is only performed once by checking the
_initialized attribute. If the instance is already initialized, the method
returns immediately. Otherwise, it proceeds to load the configuration and
validate it.
Args:
*args: Variable length argument list.
**kwargs: Arbitrary keyword arguments.
Attributes:
args (EHSArguments): An instance of EHSArguments containing the
configuration file path.
MQTT (dict): MQTT configuration settings loaded from the YAML file.
GENERAL (dict): General configuration settings loaded from the YAML file.
SERIAL (dict): Serial configuration settings loaded from the YAML file.
"""
if self._initialized:
return
self._initialized = True
super().__init__(*args, **kwargs)
logger.debug("init EHSConfig")
self.args = EHSArguments()
with open(self.args.CONFIGFILE, mode='r') as file:
config = yaml.safe_load(file)
self.MQTT = config.get('mqtt')
self.GENERAL = config.get('general')
self.SERIAL = config.get('serial')
logger.debug(f"Configuration loaded: {config}")
self.validate()
def validate(self):
"""
Validates the configuration parameters for the EHS Sentinel application.
This method checks the presence and validity of various configuration parameters
such as NASA repository file, serial device, baudrate, MQTT broker URL, broker port,
and MQTT credentials. It raises a ConfigException if any required parameter is missing
or invalid. Additionally, it sets default values for optional parameters if they are not provided.
Raises:
ConfigException: If any required configuration parameter is missing or invalid.
"""
if os.path.isfile(self.GENERAL['nasaRepositoryFile']):
with open(self.GENERAL['nasaRepositoryFile'], mode='r') as file:
self.NASA_REPO = yaml.safe_load(file)
else:
raise ConfigException(argument=self.GENERAL['nasaRepositoryFile'], message="NASA Respository File is missing")
if 'silentMode' not in self.GENERAL:
self.GENERAL['silentMode'] = True
if 'protocolFile' not in self.GENERAL:
self.GENERAL['protocolFile'] = None
if 'device' not in self.SERIAL:
raise ConfigException(argument=self.SERIAL['device'], message="serial device config parameter is missing")
if 'baudrate' not in self.SERIAL:
raise ConfigException(argument=self.SERIAL['baudrate'], message="serial baudrate config parameter is missing")
if 'broker-url' not in self.MQTT:
raise ConfigException(argument=self.MQTT['broker-url'], message="mqtt broker-url config parameter is missing")
if 'broker-port' not in self.MQTT:
raise ConfigException(argument=self.MQTT['broker-port'], message="mqtt broker-port parameter is missing")
if 'homeAssistantAutoDiscoverTopic' not in self.MQTT:
self.MQTT['homeAssistantAutoDiscoverTopic'] = ""
if 'useCamelCaseTopicNames' not in self.MQTT:
self.MQTT['useCamelCaseTopicNames'] = False
if 'topicPrefix' not in self.MQTT:
self.MQTT['topicPrefix'] = "ehsSentinel"
if 'client-id' not in self.MQTT:
self.MQTT['client-id'] = "ehsSentinel"
if 'user' not in self.MQTT and 'password' in self.MQTT:
raise ConfigException(argument=self.SERIAL['device'], message="mqtt user parameter is missing")
if 'password' not in self.MQTT and 'user' in self.MQTT:
raise ConfigException(argument=self.SERIAL['device'], message="mqtt password parameter is missing")

64
EHSExceptions.py Normal file
View File

@@ -0,0 +1,64 @@
class EHSException(Exception):
"""Base class for exceptions in this module."""
pass
class MessageWarningException(EHSException):
"""Exception raised by message errors.
Attributes:
message -- explanation of the error
"""
def __init__(self, argument, message):
self.argument = argument
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.argument}'
class ConfigException(EHSException):
"""Exception raised by multiple Config errors.
Attributes:
message -- explanation of the error
"""
def __init__(self, argument, message="Config Parameter Exception: "):
self.argument = argument
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.argument}'
class ArgumentException(EHSException):
"""Exception raised by multiple Arguments errors.
Attributes:
message -- explanation of the error
"""
def __init__(self, argument, message="Argument is missing"):
self.argument = argument
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.argument} -> {self.message}'
class InvalidMessageTypeException(EHSException):
"""Exception raised for invalid message types.
Attributes:
message_type -- input message type which caused the error
message -- explanation of the error
"""
def __init__(self, message_type, message="Invalid message type provided"):
self.message_type = message_type
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message_type} -> {self.message}'

406
MQTTClient.py Normal file
View File

@@ -0,0 +1,406 @@
import asyncio
import os
import signal
import json
import time
import gmqtt
# Get the logger
from CustomLogger import logger
from EHSArguments import EHSArguments
from EHSConfig import EHSConfig
class MQTTClient:
"""
MQTTClient is a singleton class that manages the connection to an MQTT broker and handles
publishing and subscribing to topics. It is designed to work with Home Assistant for
auto-discovery of devices and sensors.
Attributes:
_instance (MQTTClient): The single instance of the MQTTClient class.
STOP (asyncio.Event): Event to signal stopping the MQTT client.
DEVICE_ID (str): The device ID used for MQTT topics.
config (EHSConfig): Configuration object for the MQTT client.
args (EHSArguments): Arguments object for the MQTT client.
broker (str): URL of the MQTT broker.
port (int): Port of the MQTT broker.
client_id (str): Client ID for the MQTT client.
client (gmqtt.Client): MQTT client instance.
topicPrefix (str): Prefix for MQTT topics.
homeAssistantAutoDiscoverTopic (str): Topic for Home Assistant auto-discovery.
useCamelCaseTopicNames (bool): Flag to use camel case for topic names.
known_topics (list): List to keep track of known topics.
known_devices_topic (str): Dedicated topic for storing known topics.
"""
_instance = None
STOP = asyncio.Event()
DEVICE_ID = "samsung_ehssentinel"
def __new__(cls, *args, **kwargs):
"""
Create a new instance of the MQTTClient class if one does not already exist.
This method ensures that the MQTTClient class follows the Singleton design pattern,
meaning only one instance of the class can exist at any given time. If an instance
already exists, it returns the existing instance. Otherwise, it creates a new instance
and sets the _initialized attribute to False.
Args:
cls (type): The class being instantiated.
*args: Variable length argument list.
**kwargs: Arbitrary keyword arguments.
Returns:
MQTTClient: The single instance of the MQTTClient class.
"""
if not cls._instance:
cls._instance = super(MQTTClient, cls).__new__(cls)
cls._instance._initialized = False
return cls._instance
def __init__(self):
"""
Initialize the MQTTClient instance.
This constructor initializes the MQTT client with the configuration
provided by the EHSConfig and EHSArguments classes. It sets up the
MQTT broker connection details, client ID, and authentication credentials
if provided. It also assigns callback functions for various MQTT events
such as connect, disconnect, message, and subscribe. Additionally, it
initializes the topic prefix, Home Assistant auto-discover topic, and
topic naming convention.
Attributes:
config (EHSConfig): Configuration object for the MQTT client.
args (EHSArguments): Argument parser object for the MQTT client.
broker (str): URL of the MQTT broker.
port (int): Port number of the MQTT broker.
client_id (str): Client ID for the MQTT connection.
client (gmqtt.Client): gmqtt client instance.
topicPrefix (str): Prefix for MQTT topics.
homeAssistantAutoDiscoverTopic (str): Topic for Home Assistant auto-discovery.
useCamelCaseTopicNames (bool): Flag to use camel case for topic names.
known_topics (list): List to keep track of known topics.
known_devices_topic (str): Dedicated topic for storing known topics.
"""
if self._initialized:
return
self.config = EHSConfig()
self.args = EHSArguments()
self._initialized = True
self.broker = self.config.MQTT['broker-url']
self.port = self.config.MQTT['broker-port']
self.client_id = self.config.MQTT['client-id']
self.client = gmqtt.Client(self.client_id, logger=logger)
self.client.on_connect = self.on_connect
self.client.on_disconnect = self.on_disconnect
self.client.on_message = self.on_message
self.client.on_subscribe = self.on_subscribe
if self.config.MQTT['user'] and self.config.MQTT['password']:
self.client.set_auth_credentials(self.config.MQTT['user'], self.config.MQTT['password'])
self.topicPrefix = self.config.MQTT['topicPrefix']
self.homeAssistantAutoDiscoverTopic = self.config.MQTT['homeAssistantAutoDiscoverTopic']
self.useCamelCaseTopicNames = self.config.MQTT['useCamelCaseTopicNames']
self.initialized = True
self.known_topics: list = list() # Set to keep track of known topics
self.known_devices_topic = "known/devices" # Dedicated topic for storing known topics
async def connect(self):
"""
Asynchronously connects to the MQTT broker and optionally clears the known devices topic.
This method logs the connection attempt, connects to the MQTT broker using the specified
broker address and port, and sets the keepalive interval. If the CLEAN_KNOWN_DEVICES
argument is set to True, it publishes an empty message to the known devices topic to clear it.
Args:
None
Returns:
None
Raises:
Any exceptions raised by the underlying MQTT client library during connection.
"""
logger.info("[MQTT] Connecting to broker...")
await self.client.connect(self.broker, self.port, keepalive=60, version=gmqtt.constants.MQTTv311)
if self.args.CLEAN_KNOWN_DEVICES:
self._publish(f"{self.topicPrefix.replace('/', '')}/{self.known_devices_topic}", " ", retain=True)
logger.info("Known Devices Topic have been cleared")
def subscribe_known_topics(self):
"""
Subscribes the MQTT client to known topics.
This method subscribes the MQTT client to two specific topics:
1. A topic for known devices, constructed using the topic prefix and known devices topic.
2. A status topic for Home Assistant auto-discovery.
The subscription QoS (Quality of Service) level for both topics is set to 1.
Logging:
Logs an informational message indicating that the client is subscribing to known devices topic.
Raises:
Any exceptions raised by the gmqtt.Subscription or self.client.subscribe methods.
"""
logger.info("Subscribe to known devices topic")
self.client.subscribe(
[
gmqtt.Subscription(f"{self.topicPrefix.replace('/', '')}/{self.known_devices_topic}", 1),
gmqtt.Subscription(f"{self.homeAssistantAutoDiscoverTopic}/status", 1)
]
)
def on_subscribe(self, client, mid, qos, properties):
"""
Callback function that is called when the client subscribes to a topic.
Args:
client (paho.mqtt.client.Client): The client instance for this callback.
mid (int): The message ID for the subscribe request.
qos (int): The Quality of Service level for the subscription.
properties (paho.mqtt.properties.Properties): The properties associated with the subscription.
Returns:
None
"""
logger.debug('SUBSCRIBED')
def on_message(self, client, topic, payload, qos, properties):
"""
Callback function that is triggered when a message is received on a subscribed topic.
Args:
client (paho.mqtt.client.Client): The MQTT client instance.
topic (str): The topic that the message was received on.
payload (bytes): The message payload.
qos (int): The quality of service level of the message.
properties (paho.mqtt.properties.Properties): The properties of the message.
Behavior:
- If the topic matches the known devices topic, updates the known devices set with the retained message.
- If the topic matches the Home Assistant auto-discover status topic, logs the status message and clears the known devices topic.
"""
if self.known_devices_topic in topic:
# Update the known devices set with the retained message
self.known_topics = list(filter(None, [x.strip() for x in payload.decode().split(",")]))
if f"{self.homeAssistantAutoDiscoverTopic}/status" == topic:
logger.info(f"HASS Status Messages {topic} received: {payload.decode()}")
self._publish(f"{self.topicPrefix.replace('/', '')}/{self.known_devices_topic}", " ", retain=True)
logger.info("Known Devices Topic have been cleared")
def refresh_known_devices(self, devname):
"""
Refreshes the list of known devices by publishing the updated list to the MQTT topic.
Args:
devname (str): The name of the device to be refreshed.
Returns:
None
"""
self._publish(f"{self.topicPrefix.replace('/', '')}/{self.known_devices_topic}", ",".join(self.known_topics), retain=True)
def on_connect(self, client, flags, rc, properties):
"""
Callback function for when the client receives a CONNACK response from the server.
Args:
client (paho.mqtt.client.Client): The client instance for this callback.
flags (dict): Response flags sent by the broker.
rc (int): The connection result.
properties (paho.mqtt.properties.Properties): The properties associated with the connection.
Returns:
None
Logs:
- Info: When connected successfully with result code 0.
- Error: When failed to connect with a non-zero result code.
"""
if rc == 0:
logger.info(f"Connected to MQTT with result code {rc}")
if len(self.homeAssistantAutoDiscoverTopic) > 0:
self.subscribe_known_topics()
else:
logger.error(f"Failed to connect, return code {rc}")
def on_disconnect(self, client, packet, exc=None):
"""
Callback function that is called when the client disconnects from the MQTT broker.
Args:
client (paho.mqtt.client.Client): The MQTT client instance that disconnected.
packet (paho.mqtt.client.MQTTMessage): The MQTT message packet received during disconnection.
exc (Exception, optional): The exception that caused the disconnection, if any. Defaults to None.
Logs:
Logs an info message indicating disconnection.
Logs a warning message indicating an unexpected disconnection and attempts to reconnect.
Logs an error message if reconnection fails and retries every 5 seconds.
"""
logger.info(f"Disconnected with result code ")
logger.warning("Unexpected disconnection. Reconnecting...")
while True:
try:
self.client.reconnect()
break
except Exception as e:
logger.error(f"Reconnection failed: {e}")
time.sleep(5)
def _publish(self, topic, payload, qos=0, retain=False):
"""
Publish a message to a specified MQTT topic.
Args:
topic (str): The MQTT topic to publish to.
payload (str): The message payload to publish.
qos (int, optional): The Quality of Service level for message delivery. Defaults to 0.
retain (bool, optional): If True, the message will be retained by the broker. Defaults to False.
Returns:
None
"""
logger.debug(f"MQTT Publish Topic: {topic} payload: {payload}")
self.client.publish(f"{topic}", payload, qos, retain)
#time.sleep(0.1)
def publish_message(self, name, value):
"""
Publishes a message to an MQTT topic.
This method normalizes the given name, determines the appropriate MQTT topic,
and publishes the provided value to that topic. If Home Assistant auto-discovery
is enabled, it will also handle the auto-discovery configuration.
Args:
name (str): The name of the sensor or device.
value (int, float, bool, str): The value to be published. If the value is a float,
it will be rounded to two decimal places.
Raises:
KeyError: If the name is not found in the NASA_REPO configuration.
"""
newname = f"{self._normalize_name(name)}"
if len(self.homeAssistantAutoDiscoverTopic) > 0:
sensor_type = "sensor"
if 'enum' in self.config.NASA_REPO[name]:
enum = [*self.config.NASA_REPO[name]['enum'].values()]
if all([en.lower() in ['on', 'off'] for en in enum]):
sensor_type = "binary_sensor"
topicname = f"{self.config.MQTT['homeAssistantAutoDiscoverTopic']}/{sensor_type}/{self.DEVICE_ID}_{newname.lower()}/state"
if name not in self.known_topics:
self.auto_discover_hass(topicname, name, newname, sensor_type)
else:
topicname = f"{self.topicPrefix.replace('/', '')}/{newname}"
if isinstance(value, (int, float)) and not isinstance(value, bool):
value = round(value, 2) if isinstance(value, float) and "." in f"{value}" else value
self._publish(topicname, value, qos=2, retain=False)
def auto_discover_hass(self, topicname, nameraw, namenorm, sensor_type):
"""
Automatically discovers and configures Home Assistant entities for the MQTT client.
This function creates and publishes a configuration payload for Home Assistant's MQTT discovery.
It supports both sensor and binary sensor types, and sets appropriate attributes based on the
provided sensor type and unit of measurement.
Args:
topicname (str): The MQTT topic name.
nameraw (str): The raw name of the sensor.
namenorm (str): The normalized name of the sensor.
sensor_type (str): The type of the sensor (e.g., "sensor" or "binary_sensor").
Returns:
None
"""
entity = { namenorm: {
"name": f"{namenorm}",
"object_id": f"{self.DEVICE_ID}_{namenorm.lower()}",
"unique_id": f"{self.DEVICE_ID}_{nameraw.lower()}",
"platform": sensor_type,
"value_template": "{{ value }}",
"state_topic": f"{self.config.MQTT['homeAssistantAutoDiscoverTopic']}/{sensor_type}/{self.DEVICE_ID}_{namenorm.lower()}/state",
}
}
if sensor_type == "sensor":
if len(self.config.NASA_REPO[nameraw]['unit']) > 0:
entity[namenorm]['unit_of_measurement'] = self.config.NASA_REPO[nameraw]['unit']
if entity[namenorm]['unit_of_measurement'] == "\u00b0C":
entity[namenorm]['device_class'] = "temperature"
elif entity[namenorm]['unit_of_measurement'] == '%':
entity[namenorm]['device_class'] = "power_factor"
elif entity[namenorm]['unit_of_measurement'] == 'kW':
entity[namenorm]['device_class'] = "power"
elif entity[namenorm]['unit_of_measurement'] == 'rpm':
entity[namenorm]['state_class'] = "measurement"
elif entity[namenorm]['unit_of_measurement'] == 'bar':
entity[namenorm]['device_class'] = "pressure"
elif entity[namenorm]['unit_of_measurement'] == 'HP':
entity[namenorm]['device_class'] = "power"
elif entity[namenorm]['unit_of_measurement'] == 'hz':
entity[namenorm]['device_class'] = "frequency"
else:
entity[namenorm]['device_class'] = None
else:
entity[namenorm]['payload_on'] = "ON"
entity[namenorm]['payload_off'] = "OFF"
if 'state_class' in self.config.NASA_REPO[nameraw]:
entity[namenorm]['state_class'] = self.config.NASA_REPO[nameraw]['state_class']
if 'device_class' in self.config.NASA_REPO[nameraw]:
entity[namenorm]['device_class'] = self.config.NASA_REPO[nameraw]['device_class']
device = {
"device": {
"identifiers": self.DEVICE_ID,
"name": "Samsung EHS",
"manufacturer": "Samsung",
"model": "Mono HQ Quiet",
"sw_version": "1.0.0"
},
"origin": {
"name": "EHS-Sentinel",
"support_url": "https://github.com/echoDaveD/EHS-Sentinel"
},
"components": entity,
"qos": 2
}
logger.debug(f"Auto Discovery HomeAssistant Message: ")
logger.debug(f"{device}")
self._publish(f"{self.config.MQTT['homeAssistantAutoDiscoverTopic']}/device/{self.DEVICE_ID}/config",
json.dumps(device, ensure_ascii=False),
qos=2,
retain=True)
self.known_topics.append(nameraw)
self.refresh_known_devices(nameraw)
def _normalize_name(self, name):
"""
Normalize the given name based on the specified naming convention.
If `useCamelCaseTopicNames` is True, the function will:
- Remove any of the following prefixes from the name: 'ENUM_', 'LVAR_', 'NASA_', 'VAR_'.
- Convert the name to CamelCase format.
If `useCamelCaseTopicNames` is False, the function will return the name as is.
Args:
name (str): The name to be normalized.
Returns:
str: The normalized name.
"""
if self.useCamelCaseTopicNames:
prefix_to_remove = ['ENUM_', 'LVAR_', 'NASA_', 'VAR_']
# remove unnecessary prefixes of name
for prefix in prefix_to_remove:
if name.startswith(prefix):
name = name[len(prefix):]
break
name_parts = name.split("_")
tmpname = name_parts[0].lower()
# construct new name in CamelCase
for i in range(1, len(name_parts)):
tmpname += name_parts[i].capitalize()
else:
tmpname = name
return tmpname

171
MessageProcessor.py Normal file
View File

@@ -0,0 +1,171 @@
import asyncio
import logging
import traceback
import yaml
from CustomLogger import logger, setSilent
from EHSArguments import EHSArguments
from EHSConfig import EHSConfig
from EHSExceptions import MessageWarningException
from MQTTClient import MQTTClient
from NASAMessage import NASAMessage
from NASAPacket import NASAPacket
class MessageProcessor:
"""
The MessageProcessor class is responsible for handling and processing incoming messages for the EHS-Sentinel system.
It follows the singleton pattern to ensure only one instance is created. The class provides methods to process
messages, extract submessages, search for message definitions in a configuration repository, and determine the
value of message payloads based on predefined rules. It also includes logging for debugging and tracing the
message processing steps.
"""
_instance = None
def __new__(cls, *args, **kwargs):
"""
Create a new instance of the class if one does not already exist.
This method ensures that only one instance of the class is created (singleton pattern).
If an instance already exists, it returns the existing instance.
Args:
cls (type): The class being instantiated.
*args: Variable length argument list.
**kwargs: Arbitrary keyword arguments.
Returns:
MessageProcessor: The single instance of the MessageProcessor class.
"""
if not cls._instance:
cls._instance = super(MessageProcessor, cls).__new__(cls, *args, **kwargs)
cls._instance._initialized = False
return cls._instance
def __init__(self):
"""
Initializes the MessageProcessor instance.
This constructor checks if the instance has already been initialized to prevent reinitialization.
If not initialized, it sets the _initialized flag to True, logs the initialization process,
and initializes the configuration and argument handling components.
Attributes:
_initialized (bool): A flag indicating whether the instance has been initialized.
config (EHSConfig): An instance of the EHSConfig class for configuration management.
args (EHSArguments): An instance of the EHSArguments class for argument handling.
"""
if self._initialized:
return
self._initialized = True
logger.debug("init MessageProcessor")
self.config = EHSConfig()
self.args = EHSArguments()
self.mqtt = MQTTClient()
self.NASA_VAL_STORE = {}
def process_message(self, packet: NASAPacket):
"""
Processes an incoming packet .
Args:
message (list): A list of integers representing the message bytes.
Raises:
MessageWarningException: If the message is invalid due to missing end byte, incorrect length, or other processing errors.
Logs:
Various debug and info logs to trace the processing steps, including packet size, raw and hex message content, source address, capacity, and extracted message details.
"""
for msg in packet.packet_messages:
hexmsg = hex(msg.packet_message)
msgname = self.search_nasa_table(hexmsg)
if msgname is not None:
try:
msgvalue = self.determine_value(msg.packet_payload, msgname)
except Exception as e:
raise MessageWarningException(argument=msg['payload'], message=f"Value of {hexmsg:<6} couldn't be determinate, skip Message {e}")
self.protocolMessage(msg, msgname, msgvalue)
else:
logger.debug(f"Message not Found in NASA repository: {hexmsg:<6} Type: {msg.packet_message_type} Payload: {msg.packet_payload}")
def protocolMessage(self, msg: NASAMessage, msgname, msgvalue):
"""
Processes a protocol message by logging, writing to a protocol file, publishing via MQTT,
and updating internal value store. Additionally, it calculates and processes specific
derived values based on certain message names.
Args:
msg (NASAMessage): The NASA message object containing packet information.
msgname (str): The name of the message.
msgvalue (Any): The value of the message.
Side Effects:
- Logs the message details.
- Appends the message details to a protocol file if configured.
- Publishes the message via MQTT.
- Updates the internal NASA value store with the message value.
- Calculates and processes derived values for specific message names.
"""
logger.info(f"Message number: {hex(msg.packet_message):<6} {msgname:<50} Type: {msg.packet_message_type} Payload: {msgvalue}")
if self.config.GENERAL['protocolFile'] is not None:
with open(self.config.GENERAL['protocolFile'], "a") as protWriter:
protWriter.write(f"{hex(msg.packet_message):<6},{msg.packet_message_type},{msgname:<50},{msgvalue}\n")
self.mqtt.publish_message(msgname, msgvalue)
self.NASA_VAL_STORE[msgname] = msgvalue
if msgname in ['NASA_OUTDOOR_TW2_TEMP', 'NASA_OUTDOOR_TW1_TEMP', 'VAR_IN_FLOW_SENSOR_CALC']:
if all(k in self.NASA_VAL_STORE for k in ['NASA_OUTDOOR_TW2_TEMP', 'NASA_OUTDOOR_TW1_TEMP', 'VAR_IN_FLOW_SENSOR_CALC']):
self.protocolMessage(NASAMessage(packet_message=0x9999, packet_message_type=1),
"NASA_EHSSENTINEL_HEAT_OUTPUT",
round(
(
(self.NASA_VAL_STORE['NASA_OUTDOOR_TW2_TEMP'] - self.NASA_VAL_STORE['NASA_OUTDOOR_TW1_TEMP']) *
(self.NASA_VAL_STORE['VAR_IN_FLOW_SENSOR_CALC']/60)
* 4190
), 4))
if msgname in ('NASA_EHSSENTINEL_HEAT_OUTPUT', 'NASA_OUTDOOR_CONTROL_WATTMETER_ALL_UNIT'):
if all(k in self.NASA_VAL_STORE for k in ['NASA_EHSSENTINEL_HEAT_OUTPUT', 'NASA_OUTDOOR_CONTROL_WATTMETER_ALL_UNIT']):
self.protocolMessage(NASAMessage(packet_message=0x9998, packet_message_type=1),
"NASA_EHSSENTINEL_COP",
round((self.NASA_VAL_STORE['NASA_EHSSENTINEL_HEAT_OUTPUT'] / self.NASA_VAL_STORE['NASA_OUTDOOR_CONTROL_WATTMETER_ALL_UNIT']/1000.), 3))
def search_nasa_table(self, address):
"""
Searches for a specific address in the NASA_REPO configuration and returns the corresponding key.
Args:
address (str): The address to search for in the NASA_REPO.
Returns:
str: The key associated with the given address if found, otherwise None.
"""
for key, value in self.config.NASA_REPO.items():
if value['address'].lower() == address:
return key
def determine_value(self, rawvalue, msgname):
"""
Determines the processed value from a raw byte input based on the message name configuration.
Args:
rawvalue (bytes): The raw byte value to be processed.
msgname (str): The name of the message which determines the processing rules.
Returns:
float or str: The processed value, which could be a numerical value or an enumerated string.
Raises:
Warning: Logs a warning if the arithmetic function cannot be applied and uses the raw value instead.
"""
arithmetic = self.config.NASA_REPO[msgname]['arithmetic'].replace("value", 'packed_value')
packed_value = int.from_bytes(rawvalue, byteorder='big', signed=True)
if len(arithmetic) > 0:
try:
value = eval(arithmetic)
except Exception as e:
logger.warning(f"Arithmetic Function couldn't been applied, using raw value: arithmetic = {arithmetic} {e}")
value = packed_value
else:
value = packed_value
if self.config.NASA_REPO[msgname]['type'] == 'ENUM':
if 'enum' in self.config.NASA_REPO[msgname]:
value = self.config.NASA_REPO[msgname]['enum'][int.from_bytes(rawvalue, byteorder='big')].upper()
else:
value = f"Unknown enum value: {value}"
else:
value = round(value, 3)
return value

61
NASAMessage.py Normal file
View File

@@ -0,0 +1,61 @@
class NASAMessage:
"""
A class to represent a NASA message.
Attributes
----------
packet_message : int
The message packet identifier.
packet_message_type : int
The type of the message packet.
packet_payload : bytes
The payload of the message packet in bytes.
Methods
-------
__str__():
Returns a string representation of the NASAMessage instance.
__repr__():
Returns a string representation of the NASAMessage instance.
"""
def __init__(self, packet_message=0x000, packet_message_type=0, packet_payload=[0]):
"""
Constructs all the necessary attributes for the NASAMessage object.
Parameters
----------
packet_message : int, optional
The message packet identifier (default is 0x000).
packet_message_type : int, optional
The type of the message packet (default is 0).
packet_payload : list, optional
The payload of the message packet as a list of integers (default is [0]).
"""
"""
Returns a string representation of the NASAMessage instance.
Returns
-------
str
A string representation of the NASAMessage instance.
"""
"""
Returns a string representation of the NASAMessage instance.
Returns
-------
str
A string representation of the NASAMessage instance.
"""
self.packet_message: int = packet_message
self.packet_message_type: int = packet_message_type
self.packet_payload: bytes = bytes([int(hex(x), 16) for x in packet_payload])
def __str__(self):
return (
f"NASAMessage(\n"
f" packet_message={self.packet_message} ({hex(self.packet_message)}),\n"
f" packet_message_type={self.packet_message_type} ({hex(self.packet_message_type)}),\n"
f" packet_payload={self.packet_payload} ({self.packet_payload.hex()})\n"
f")"
)
def __repr__(self):
return self.__str__()

308
NASAPacket.py Normal file
View File

@@ -0,0 +1,308 @@
from enum import Enum
from NASAMessage import NASAMessage
class AddressClassEnum(Enum):
"""
Enum class representing various address classes for NASA packets.
Attributes:
Outdoor (int): Address class for outdoor units (0x10).
HTU (int): Address class for HTU units (0x11).
Indoor (int): Address class for indoor units (0x20).
ERV (int): Address class for ERV units (0x30).
Diffuser (int): Address class for diffuser units (0x35).
MCU (int): Address class for MCU units (0x38).
RMC (int): Address class for RMC units (0x40).
WiredRemote (int): Address class for wired remote units (0x50).
PIM (int): Address class for PIM units (0x58).
SIM (int): Address class for SIM units (0x59).
Peak (int): Address class for peak units (0x5A).
PowerDivider (int): Address class for power divider units (0x5B).
OnOffController (int): Address class for on/off controller units (0x60).
WiFiKit (int): Address class for WiFi kit units (0x62).
CentralController (int): Address class for central controller units (0x65).
DMS (int): Address class for DMS units (0x6A).
JIGTester (int): Address class for JIG tester units (0x80).
BroadcastSelfLayer (int): Address class for broadcast self layer (0xB0).
BroadcastControlLayer (int): Address class for broadcast control layer (0xB1).
BroadcastSetLayer (int): Address class for broadcast set layer (0xB2).
BroadcastCS (int): Address class for broadcast CS (0xB3).
BroadcastControlAndSetLayer (int): Address class for broadcast control and set layer (0xB3).
BroadcastModuleLayer (int): Address class for broadcast module layer (0xB4).
BroadcastCSM (int): Address class for broadcast CSM (0xB7).
BroadcastLocalLayer (int): Address class for broadcast local layer (0xB8).
BroadcastCSML (int): Address class for broadcast CSML (0xBF).
Undefined (int): Address class for undefined units (0xFF).
"""
Outdoor = 0x10
HTU = 0x11
Indoor = 0x20
ERV = 0x30
Diffuser = 0x35
MCU = 0x38
RMC = 0x40
WiredRemote = 0x50
PIM = 0x58
SIM = 0x59
Peak = 0x5A
PowerDivider = 0x5B
OnOffController = 0x60
WiFiKit = 0x62
CentralController = 0x65
DMS = 0x6A
JIGTester = 0x80
BroadcastSelfLayer = 0xB0
BroadcastControlLayer = 0xB1
BroadcastSetLayer = 0xB2
BroadcastCS = 0xB3
BroadcastControlAndSetLayer = 0xB3
BroadcastModuleLayer = 0xB4
BroadcastCSM = 0xB7
BroadcastLocalLayer = 0xB8
BroadcastCSML = 0xBF
Undefined = 0xFF
class PacketType(Enum):
"""
Enum class representing different types of packets in the EHS-Sentinel system.
Attributes:
StandBy (int): Represents a standby packet type with a value of 0.
Normal (int): Represents a normal packet type with a value of 1.
Gathering (int): Represents a gathering packet type with a value of 2.
Install (int): Represents an install packet type with a value of 3.
Download (int): Represents a download packet type with a value of 4.
"""
StandBy = 0
Normal = 1
Gathering = 2
Install = 3
Download = 4
class DataType(Enum):
"""
Enum representing different types of data operations.
Attributes:
Undefined (int): Represents an undefined data type (0).
Read (int): Represents a read operation (1).
Write (int): Represents a write operation (2).
Request (int): Represents a request operation (3).
Notification (int): Represents a notification operation (4).
Response (int): Represents a response operation (5).
Ack (int): Represents an acknowledgment (6).
Nack (int): Represents a negative acknowledgment (7).
"""
Undefined = 0
Read = 1
Write = 2
Request = 3
Notification = 4
Resposne = 5
Ack = 6
Nack = 7
class NASAPacket:
"""
A class to represent a NASA Packet.
Attributes
----------
_packet_raw : bytearray
Raw packet data.
packet_start : int
Start byte of the packet.
packet_size : int
Size of the packet.
packet_source_address_class : AddressClassEnum
Source address class of the packet.
packet_source_channel : int
Source channel of the packet.
packet_source_address : int
Source address of the packet.
packet_dest_address_class : AddressClassEnum
Destination address class of the packet.
packet_dest_channel : int
Destination channel of the packet.
packet_dest_address : int
Destination address of the packet.
packet_information : int
Information field of the packet.
packet_version : int
Version of the packet.
packet_retry_count : int
Retry count of the packet.
packet_type : PacketType
Type of the packet.
packet_data_type : DataType
Data type of the packet.
packet_number : int
Number of the packet.
packet_capacity : int
Capacity of the packet.
packet_messages : list[NASAMessage]
List of messages in the packet.
packet_crc16 : int
CRC16 checksum of the packet.
packet_end : int
End byte of the packet.
Methods
-------
parse(packet: bytearray):
Parses the given packet data.
_extract_messages(depth: int, capacity: int, msg_rest: bytearray, return_list: list):
Recursively extracts messages from the packet.
__str__():
Returns a string representation of the NASAPacket.
__repr__():
Returns a string representation of the NASAPacket.
"""
def __init__(self):
self._packet_raw: bytearray = None
self.packet_start: int = None
self.packet_size: int = None
self.packet_source_address_class: AddressClassEnum = None
self.packet_source_channel: int = None
self.packet_source_address: int = None
self.packet_dest_address_class: AddressClassEnum = None
self.packet_dest_channel: int = None
self.packet_dest_address: int = None
self.packet_information: int = None
self.packet_version: int = None
self.packet_retry_count: int = None
self.packet_type: PacketType = None
self.packet_data_type: DataType = None
self.packet_number: int = None
self.packet_capacity: int = None
self.packet_messages: list[NASAMessage] = None
self.packet_crc16: int = None
self.packet_end: int = None
def parse(self, packet: bytearray):
"""
Parses a given bytearray packet and extracts various fields into the object's attributes.
Args:
packet (bytearray): The packet to be parsed.
Raises:
ValueError: If the packet length is less than 14 bytes.
Attributes:
packet_start (int): The start byte of the packet.
packet_size (int): The size of the packet.
packet_source_address_class (AddressClassEnum): The source address class of the packet.
packet_source_channel (int): The source channel of the packet.
packet_source_address (int): The source address of the packet.
packet_dest_address_class (AddressClassEnum): The destination address class of the packet.
packet_dest_channel (int): The destination channel of the packet.
packet_dest_address (int): The destination address of the packet.
packet_information (bool): Information flag of the packet.
packet_version (int): Version of the packet.
packet_retry_count (int): Retry count of the packet.
packet_type (PacketType): Type of the packet.
packet_data_type (DataType): Data type of the packet.
packet_number (int): Number of the packet.
packet_capacity (int): Capacity of the packet.
packet_crc16 (int): CRC16 checksum of the packet.
packet_end (int): The end byte of the packet.
packet_messages (list): Extracted messages from the packet.
"""
self._packet_raw = packet
if len(packet) < 14:
raise ValueError("Data too short to be a valid NASAPacket")
self.packet_start = packet[0]
self.packet_size = ((packet[1] << 8) | packet[2])
self.packet_source_address_class = AddressClassEnum(packet[3])
self.packet_source_channel = packet[4]
self.packet_source_address = packet[5]
self.packet_dest_address_class = AddressClassEnum(packet[6])
self.packet_dest_channel = packet[7]
self.packet_dest_address = packet[8]
self.packet_information = (int(packet[9]) & 128) >> 7 == 1
self.packet_version = (int(packet[9]) & 96) >> 5
self.packet_retry_count = (int(packet[9]) & 24) >> 3
self.packet_type = PacketType((int(packet[10]) & 240) >> 4)
self.packet_data_type = DataType(int(packet[10]) & 15)
self.packet_number = packet[11]
self.packet_capacity = packet[12]
self.packet_crc16 = ((packet[-3] << 8) | packet[-2]) + 2
self.packet_end = packet[-1]
self.packet_messages = self._extract_messages(0, self.packet_capacity, packet[13:-3], [])
def _extract_messages(self, depth: int, capacity: int, msg_rest: bytearray, return_list: list):
"""
Recursively extracts messages from a bytearray and appends them to a list.
Args:
depth (int): The current depth of recursion.
capacity (int): The maximum allowed depth of recursion.
msg_rest (bytearray): The remaining bytes to be processed.
return_list (list): The list to which extracted messages are appended.
Returns:
list: The list of extracted messages.
Raises:
ValueError: If the message type is unknown, the capacity is invalid for a structure type message,
or the payload size exceeds 255 bytes.
"""
if depth > capacity or len(msg_rest) <= 2:
return return_list
message_number = (msg_rest[0] << 8) | msg_rest[1]
message_type = (message_number & 1536) >> 9
if message_type == 0:
payload_size = 1
elif message_type == 1:
payload_size = 2
elif message_type == 2:
payload_size = 4
elif message_type == 3:
payload_size = len(msg_rest)
if capacity != 1:
raise ValueError(message="Message with structure type must have capacity of 1.")
else:
raise ValueError(message=f"Mssage type unknown: {message_type}")
payload = msg_rest[2:2 + payload_size]
if len(payload) > 255:
raise ValueError(f"Payload for Submessage {hex(message_number)} too large at index {depth}: {len(payload)} bytes.")
return_list.append(NASAMessage(packet_message=message_number, packet_message_type=message_type, packet_payload=payload))
return self._extract_messages(depth+1, capacity, msg_rest[2 + payload_size:], return_list)
def __str__(self):
text = f"NASAPacket(\n"
text += f" start={self.packet_start} ({hex(self.packet_start)}),\n"
text += f" size={self.packet_size} ({hex(self.packet_size)}),\n"
text += f" source_address_class={self.packet_source_address_class} ({hex(self.packet_source_address_class.value)}),\n"
text += f" source_channel={self.packet_source_channel} ({hex(self.packet_source_channel)}),\n"
text += f" source_address={self.packet_source_address} ({hex(self.packet_source_address)}),\n"
text += f" dest_address_class={self.packet_dest_address_class} ({hex(self.packet_dest_address_class.value)}),\n"
text += f" dest_channel={self.packet_dest_channel} ({hex(self.packet_dest_channel)}),\n"
text += f" dest_address={self.packet_dest_address} ({hex(self.packet_dest_address)}),\n"
text += f" information={self.packet_information},\n"
text += f" version={self.packet_version} ({hex(self.packet_version)}),\n"
text += f" retry_count={self.packet_retry_count} ({hex(self.packet_retry_count)}),\n"
text += f" type={self.packet_type} ({hex(self.packet_type.value)}),\n"
text += f" data_type={self.packet_data_type} ({hex(self.packet_data_type.value)}),\n"
text += f" number={self.packet_number} ({hex(self.packet_number)}),\n"
text += f" capacity={self.packet_capacity} ({hex(self.packet_capacity)}),\n"
text += f" messages=[\n"
for msg in self.packet_messages:
lines = f"{msg}".splitlines()
text += f" {lines[0]}\n"
for line in lines[1:-1]:
text += f" {line}\n"
text += f" {lines[-1]}\n"
text += " ],\n"
text += f" crc16={self.packet_crc16} ({hex(self.packet_crc16)}),\n"
text += f" end={self.packet_end} ({hex(self.packet_end)})\n"
text += f")"
return text
def __repr__(self):
return self.__str__()
# Example usage:
# packet = NASAPacket()
# packet.parse(bytearray([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]))
# print(packet)

193
README.md
View File

@@ -1,2 +1,193 @@
# EHS-Sentinel
EHS Sentinel written in python which reads Samsung EHS serial Data and published it to MQTT/Home Asistent
EHS Sentinel written in python which reads Samsung EHS serial Data and published it to MQTT.
If want, you can activate the Home Assistent MQTT Auto Discovery Format, then the Messages will be sent in Home Assistent format.
There are already some solutions, but most of them are limited to just a few data points.
Since extending these was often too difficult, I have written a script here which lists almost all known data points of the Samsung EHS (source: https://wiki.myehs.eu/wiki/NASA_Protocol) in a YAML file as a repository `data/NasaRepository` and the entries there were supplemented by a few Relavante HomeAssistant attributes
In addition, a few data points are generated from others, such as COP and Heat Output.
# Installation
## Simple
1. Just clone the repository
`git clone https://github.com/echoDaveD/EHS-Sentinel`
2. Install the requierments
`pip install -r requirements.txt`
3. Copy the `data/config.yml` and provide your Configuration
4. Start the Application:
`python3 startEHSSentinel.py --configfile config.yml`
## Systemd Service
1. Just clone the repository
`git clone https://github.com/echoDaveD/EHS-Sentinel`
2. Install the requierments
`pip install -r requirements.txt`
3. Copy the `data/config.yml` and provide your Configuration
4. Change to ehs-sentinel.service file as followed:
`ExecStart = python3 <Path of the script you want to run>` <- provide here to path to your folder where startEHSSentinel.py is
sample: `ExecStart = python3 /root/EHS-Sentinel/startEHSSentinel.py --configfile /root/EHS-Sentinel/config.yml`
5. Change your `config.yml` to absolut paths:
`nasaRepositoryFile: /root/EHS-Sentinel/data/NasaRepository.yml`
6. Copy the service File to your systemd folder:
`cp ehs-sentinel.service /etc/systemd/system`
7. Enable the new service
`systemctl enable ehs-sentinel`
8. Reload deamon
`systemctl daemon-reload`
9. Start the Service
`systemctl start ehs-sentinel`
10. check if anything is fine
`systemctl status ehs-sentinel`
11. If your want to check the journal logs
`journalctl | grep ehsSentinel`
# Configuration
## Command-Line Arguments
The `EHSArguments` class handles command-line arguments for the EHS-Sentinel script. Below is a detailed explanation of each argument and its usage.
### Arguments
- **--configfile** (required)
- Type: `str`
- Description: Path to the configuration file.
- Example: `--configfile config.yml`
- **--dumpfile** (optional)
- Type: `str`
- Description: File path for where the dump file should be written to or read from if the `--dryrun` flag is set.
- Example: `--dumpfile dumpfile.txt`
- **--dryrun** (optional)
- Type: `bool`
- Description: Run the script in dry run mode. Data will be read from the dump file.
- Example: `--dryrun`
- **--clean-known-devices** (optional)
- Type: `bool`
- Description: Cleans the known devices topic on startup. Relevant for Home Assistant Auto Discovery, this option forces to resend the Device Configuration Autodiscovery Messages.
- Example: `--clean-known-devices`
- **-v, --verbose** (optional)
- Type: `bool`
- Description: Enable verbose mode.
- Example: `-v` or `--verbose`
### Example Usage
To run the EHS-Sentinel script with the required configuration file and optional arguments, use the following command:
```sh
python3 startEHSSentinel.py --configfile config.yml --dumpfile dumpfile.txt --dryrun --clean-known-devices -v
```
## Configuration File: `config.yml`
The `config.yml` file contains configuration settings for the EHS-Sentinel project. This file is used to configure general settings, serial connection parameters, and MQTT broker details. Below is a detailed explanation of each section and its parameters.
### General Settings
- **nasaRepositoryFile**: Path to the NASA repository file.
- Default: `data/NasaRepository.yml`
- **silentMode**: Boolean flag to enable or disable silent mode. In Silent Mode only Logmessages above WARNING are printed out (for production use to not spam your systemlog)
- Default: `True`
- **protocolFile**: Path to the protocol file. (not set in Sample config.yml)
- Example: `prot.csv`
### Serial Connection Settings
- **device**: The serial device URL.
- Example: `/dev/ttyUSB0`
- **baudrate**: The baud rate for the serial connection.
- Example: `9600`
### MQTT Broker Settings
- **broker-url**: The URL of the MQTT broker.
- Example: `123.45.6.69`
- **broker-port**: The port number of the MQTT broker.
- Example: `1883`
- **client-id**: The client ID to use when connecting to the MQTT broker.
- Deafult: `EHS-Sentinel`
- **user**: The username for authenticating with the MQTT broker.
- Example: `user`
- **password**: The password for authenticating with the MQTT broker.
- Example: `bigBabaBubuPa$$word1`
- **homeAssistantAutoDiscoverTopic**: The topic prefix for Home Assistant auto-discovery. This Topicprefix must be the same as in Home Assistant MQTT Integration Settings
- Example: `homeassistant`
- **useCamelCaseTopicNames**: Boolean flag to enable or disable the use of camel case for topic names.
- Example: `True`
- **topicPrefix**: The prefix to use for MQTT topics. (Is used when homeassistant is not set or empty)
- Example: `ehsSentinel`
### Example Configuration
```yaml
general:
nasaRepositoryFile: data/NasaRepository.yml
silentMode: False
protocolFile: prot.csv
serial:
device: /dev/ttyUSB0
baudrate: 9600
mqtt:
broker-url: 123.45.6.69
broker-port: 1883
client-id: EHS-Sentinel
user: user
password: bigBabaBubuPa$$word1
homeAssistantAutoDiscoverTopic: "homeassistant"
useCamelCaseTopicNames: True
topicPrefix: ehsSentinel
```
# Debugging
If you want to debug the App or just play around or even make some Changes, you can use the Dumpfile mode to be independent of the serial port and your production system.
## Creating Dump Files
To generate a Dumpfile just start the App with the `--dumpfile` Argument an let it run for a few minutes. 5-10 minutes has proven to be a good amount of time.
`python3 startEHSSentinel.py --configfile config.yml --dumpfile dump.txt`
to abort the Script jost Keyinterrupt with strg+c.
## Using Dumpfile as Input (no Serial)
If you have generated an Dumpfile you can use this to run in drymode so, the EHS-Sentinel is reading your dumpfile instead of Serial Port.
`python3 startEHSSentinel.py --configfile config.yml --dumpfile dump.txt --dryrun`
### Additional Commands
if you want to see how many uniquie Messages have been collected in the Dumpfile, here some commands:
1. Run the Dumpfile generatation with activated protocol file in the Config file.
2. search unique measerments
`sort -u -t, -k1,3 prot.csv > prot_uniq.csv`
3. count lines
`wc -l prot_uniq.csv`
# Changelog
### v0.1.0Beta - 2025-02-08
- Initial Commit

5809
data/NasaRepository.yml Normal file

File diff suppressed because it is too large Load Diff

15
data/config.yml Normal file
View File

@@ -0,0 +1,15 @@
general:
nasaRepositoryFile: data/NasaRepository.yml
silentMode: True
serial:
device: /dev/ttyUSB0
baudrate: 9600
mqtt:
broker-url: 111.111.11.1
broker-port: 1883
client-id: ehsSentinel
user:
password:
homeAssistantAutoDiscoverTopic: "hass"
useCamelCaseTopicNames: True
topicPrefix: ehsSentinel

View File

@@ -0,0 +1,2 @@
[50, 0, 60, 16, 0, 0, 176, 0, 255, 192, 20, 27, 13, 2, 2, 255, 255, 4, 16, 0, 0, 0, 0, 4, 27, 0, 32, 255, 255, 128, 0, 0, 128, 5, 255, 128, 23, 0, 128, 25, 0, 128, 26, 0, 128, 33, 1, 128, 50, 1, 128, 51, 2, 128, 60, 0, 128, 69, 0, 63, 195, 52]
[50, 0, 62, 16, 0, 0, 176, 0, 255, 192, 20, 28, 16, 128, 99, 1, 128, 102, 0, 128, 119, 0, 128, 120, 2, 128, 121, 0, 128, 122, 0, 128, 123, 0, 128, 124, 0, 128, 125, 0, 128, 126, 0, 128, 127, 255, 128, 131, 0, 128, 142, 255, 128, 169, 0, 128, 175, 0, 128, 177, 0, 145, 101, 52]

14
ehs-sentinel.service Normal file
View File

@@ -0,0 +1,14 @@
[Unit]
Description = EHS-Sentinel Reads Serial port data from a Samsung Heatpump and published the Measurements to MQTT
After = network.target
[Service]
Type = simple
ExecStart = python3 <Path of the script you want to run>
Restart = on-failure
SyslogIdentifier = ehsSentinel
RestartSec = 5
TimeoutStartSec = infinity
[Install]
WantedBy = multi-user.target

132
helpertils/helper.py Normal file
View File

@@ -0,0 +1,132 @@
import argparse
import configparser
import yaml
"""
This script provides helper functions for processing NASA table data and merging YAML files.
Functions:
parse_arguments():
Parses command-line arguments to get the function name to execute.
nasatable2dict():
Reads data from 'nasa_table.txt' and 'nasa_type_table.txt', processes it, and writes the output to 'nasa_data2.yaml'.
yaml_merge():
Merges data from 'nasa_data.yaml' and 'nasa_data2.yaml', and writes the merged output to 'nasa_data3.yaml'.
main():
Main function that calls the appropriate function based on the command-line argument.
"""
def parse_arguments():
parser = argparse.ArgumentParser(description="EHS2MQTT Helper Script")
parser.add_argument('functionname', type=str, help='Put the function name here')
arg = parser.parse_args()
return arg.functionname
def nasatable2dict():
with open('nasa_table.txt', 'r') as file:
lines = file.readlines()
data = {}
for line in lines:
parts = line.strip().split('||')
valid_name = parts[1].strip()
if valid_name.endswith('?') or len(parts[1].strip()) == 0:
valid_name = parts[2].strip()
if valid_name.endswith('?'):
valid_name = ''
if len(valid_name) > 0:
data[parts[0].strip()] = {
'label': parts[1].strip() if (len(parts[2].strip()) == 0 and not parts[2].strip().endswith('??')) else parts[2].strip(),
'description': parts[3].strip(),
'remarks': parts[4].strip(),
'type': '',
'signed': '',
'unit': '',
'arithmetic': '',
}
with open('nasa_type_table.txt', 'r') as file:
lines = file.readlines()
types = {}
for line in lines:
parts = line.strip().split('||')
types[parts[0].strip()] = {
'type': parts[1].strip(),
'signed': parts[2].strip(),
'unit': parts[3].strip(),
'arithmetic': parts[4].strip()
}
for key in data:
if key in types:
data[key]['type'] = types[key]['type']
data[key]['signed'] = types[key]['signed']
data[key]['unit'] = types[key]['unit']
data[key]['arithmetic'] = types[key]['arithmetic']
config = {}
for key, value in data.items():
print(f"Adding {value['label']} with address {value}")
if len(value['label']) > 0:
config[value['label']] = {
'address': key,
'description': value['description'],
'remarks': value['remarks'],
'type': value['type'],
'signed': value['signed'],
'unit': value['unit'],
'arithmetic': value['arithmetic']
}
with open('nasa_data2.yaml', 'w') as configfile:
yaml.dump(config, configfile, default_flow_style=False)
print(data)
def yaml_merge():
with open('nasa_data.yaml', 'r') as configfile:
yaml1 = yaml.safe_load(configfile)
with open('nasa_data2.yaml', 'r') as configfile:
yaml2 = yaml.safe_load(configfile)
yaml3 = {}
for key2, value2 in yaml2.items():
found = False
for key, value in yaml1.items():
if(value['address'] == value2['address']):
found = True
if key2 != key:
print(f"Key {key} rewrite with {key2}")
yaml3[key2] = value
else:
yaml3[key] = value
break
if key2 == key:
print(f"Key {key2} already exists")
break
if not found:
print(f"Adding {key2} with address {value2['address']}")
yaml3[key2] = value2
with open('nasa_data3.yaml', 'w') as configfile:
yaml.dump(yaml3, configfile, default_flow_style=False)
def main():
funktion = parse_arguments()
if funktion.lower() == "nasatable2dict":
print("Calling nasatable2dict")
nasatable2dict()
if funktion.lower() == "yaml_merge":
print("Calling yaml_merge")
yaml_merge()
if __name__ == "__main__":
main()

764
helpertils/nasa_table.txt Normal file
View File

@@ -0,0 +1,764 @@
0x0000 || || NASA_IM_MASTER_NOTIFY || ||
0x0004 || || NASA_INSPECTION_MODE || ||
0x0007 || || NASA_GATHER_INFORMATION || ||
0x0008 || || NASA_GATHER_INFORMATION_COUNT || ||
0x000A || || NASA_ENABLEDOWNLOAD || ||
0x000D || || NASA_DETECTION_TYPE || ||
0x000E || || NASA_PEAK_LEVEL || ||
0x000F || || NASA_PEAK_MODE || ||
0x0010 || || NASA_PEAK_CONTROL_PERIOD || ||
0x0011 || || NASA_POWER_MANUFACTURE || ||
0x0012 || || NASA_POWER_CHANNEL1_TYPE || ||
0x0013 || || NASA_POWER_CHANNEL2_TYPE || ||
0x0014 || || NASA_POWER_CHANNEL3_TYPE || ||
0x0015 || || NASA_POWER_CHANNEL4_TYPE || ||
0x0016 || || NASA_POWER_CHANNEL5_TYPE || ||
0x0017 || || NASA_POWER_CHANNEL6_TYPE || ||
0x0018 || || NASA_POWER_CHANNEL7_TYPE || ||
0x0019 || || NASA_POWER_CHANNEL8_TYPE || ||
0x001A || || NASA_POWER_CHANNEL1_USED || ||
0x001B || || NASA_POWER_CHANNEL2_USED || ||
0x001C || || NASA_POWER_CHANNEL3_USED || ||
0x001D || || NASA_POWER_CHANNEL4_USED || ||
0x001E || || NASA_POWER_CHANNEL5_USED || ||
0x001F || || NASA_POWER_CHANNEL6_USED || ||
0x0020 || || NASA_POWER_CHANNEL7_USED || ||
0x0021 || || NASA_POWER_CHANNEL8_USED || ||
0x0023 || || NASA_STANDBY_MODE || ||
0x0025 || ENUM_AD_MULTI_TENANT_NO || || WiFi Kit Multi Tenant No. ||
0x0202 || VAR_AD_ERROR_CODE1 || NASA_ERROR_CODE1 || Error code ||
0x0203 || || NASA_ERROR_CODE2 || ||
0x0204 || || NASA_ERROR_CODE3 || ||
0x0205 || || NASA_ERROR_CODE4 || ||
0x0206 || || NASA_ERROR_CODE5 || ||
0x0207 || VAR_AD_INSTALL_NUMBER_INDOOR || NASA_OUTDOOR_INDOORCOUNT || Number of indoor units connected ||
0x0208 || || NASA_OUTDOOR_ERVCOUNT || ||
0x0209 || || NASA_OUTDOOR_EHSCOUNT || ||
0x0210 || || NASA_NET_ADDRESS || ||
0x0211 || VAR_AD_INSTALL_NUMBER_MCU || NASA_OUTDOOR_MCUCOUNT || Number of connected MCUs ||
0x0213 || || NASA_DEMAND_SYNC_TIME || ||
0x0214 || || NASA_PEAK_TARGET_DEMAND || ||
0x0217 || || NASA_PNP_NET_ADDRESS || PNP only ||
0x0401 || LVAR_AD_ADDRESS_MAIN || NASA_CONFIRM_ADDRESS || ||
0x0402 || LVAR_AD_ADDRESS_RMC || NASA_RMCADDRESS || || LogicalAnd 0xFF
0x0403 || || NASA_RANDOM_ADDRESS || ||
0x0406 || || NASA_ALL_POWER_CONSUMPTION_SET || Total instantaneous power consumption ||
0x0407 || || NASA_ALL_POWER_CONSUMPTION_CUMULATIVE || Total cumulative power consumption ||
0x0408 || LVAR_AD_ADDRESS_SETUP || NASA_SETUP_ADDRESS || ||
0x0409 || LVAR_AD_INSTALL_LEVEL_ALL || NASA_ALL_REMOTE_LEVEL || ||
0x040A || LVAR_AD_INSTALL_LEVEL_OPERATION_POWER || NASA_LEVEL_POWER || ||
0x040B || LVAR_AD_INSTALL_LEVEL_OPERATION_MODE || NASA_LEVEL_OPMODE || ||
0x040C || LVAR_AD_INSTALL_LEVEL_FAN_MODE || NASA_LEVEL_FANSPEED || ||
0x040D || LVAR_AD_INSTALL_LEVEL_FAN_DIRECTION || NASA_LEVEL_AIRSWING || ||
0x040E || LVAR_AD_INSTALL_LEVEL_TEMP_TARGET || NASA_LEVEL_SETTEMP || ||
0x040F || LVAR_AD_INSTALL_LEVEL_KEEP_INDIVIDUAL_CONTROL || NASA_LEVEL_KEEP_ALTERNATIVE_MODE || ||
0x0410 || LVAR_AD_INSTALL_LEVEL_OPERATION_MODE_ONLY || NASA_LEVEL_OPMODE_LIMIT || ||
0x0411 || LVAR_AD_INSTALL_LEVEL_COOL_MODE_UPPER || NASA_LEVEL_COOL_HIGH_TEMP_LIMIT || ||
0x0412 || LVAR_AD_INSTALL_LEVEL_COOL_MODE_LOWER || NASA_LEVEL_COOL_LOW_TEMP_LIMIT || ||
0x0413 || LVAR_AD_INSTALL_LEVEL_HEAT_MODE_UPPER || NASA_LEVEL_HEAT_HIGH_TEMP_LIMIT || ||
0x0414 || LVAR_AD_INSTALL_LEVEL_HEAT_MODE_LOWER || NASA_LEVEL_HEAT_LOW_TEMP_LIMIT || ||
0x0415 || LVAR_AD_INSTALL_LEVEL_CONTACT_CONTROL || NASA_LEVEL_OUT_POINT_INPUT || ||
0x0416 || LVAR_AD_INSTALL_LEVEL_KEY_OPERATION_INPUT || NASA_LEVEL_KEY_INPUT || ||
0x0417 || LVAR_AD_?? || NASA_PNP_CONFIRM_ADDRESS || PNP only ||
0x0418 || LVAR_AD_?? || NASA_PNP_RANDOM_ADDRESS || PNP only ||
0x0419 || LVAR_AD_?? || NASA_PNP_SETUP_ADDRESS || PNP only ||
0x041B || LVAR_AD_?? || || ||
0x041C || || NASA_POWER_CHANNEL1_ELECTRIC_VALUE || ||
0x041D || || NASA_POWER_CHANNEL2_ELECTRIC_VALUE || ||
0x041E || || NASA_POWER_CHANNEL3_ELECTRIC_VALUE || ||
0x041F || || NASA_POWER_CHANNEL4_ELECTRIC_VALUE || ||
0x0420 || || NASA_POWER_CHANNEL5_ELECTRIC_VALUE || ||
0x0421 || || NASA_POWER_CHANNEL6_ELECTRIC_VALUE || ||
0x0422 || || NASA_POWER_CHANNEL7_ELECTRIC_VALUE || ||
0x0423 || || NASA_POWER_CHANNEL8_ELECTRIC_VALUE || ||
0x0434 || || NASA_PEAK_RATIO_CURRENT || ||
0x0435 || || NASA_PEAK_RATIO_POTENTIAL || ||
0x0436 || || NASA_PEAK_TOTAL_POWER || ||
0x0437 || || NASA_PEAK_CURRENT_TARGET_DEMAND || ||
0x0438 || || NASA_PEAK_FORCAST_DEMAND || ||
0x0439 || || NASA_PEAK_TOP_DEMAND || ||
0x043A || || NASA_PEAK_TARGET_POWER || ||
0x043B || || NASA_POWER_CHANNEL1_PULSEVALUE || ||
0x043C || || NASA_POWER_CHANNEL2_PULSEVALUE || ||
0x043D || || NASA_POWER_CHANNEL3_PULSEVALUE || ||
0x043E || || NASA_POWER_CHANNEL4_PULSEVALUE || ||
0x043F || || NASA_POWER_CHANNEL5_PULSEVALUE || ||
0x0440 || || NASA_POWER_CHANNEL6_PULSEVALUE || ||
0x0441 || || NASA_POWER_CHANNEL7_PULSEVALUE || ||
0x0442 || || NASA_POWER_CHANNEL8_PULSEVALUE || ||
0x0443 || || NASA_PEAK_SYNC_TIME || ||
0x0444 || || NASA_PEAK_CURRENT_DEMAND || ||
0x0445 || || NASA_PEAK_REAL_VALUE || ||
0x0448 || LVAR_AD_MCU_PORT_SETUP || || ||
0x0600 || STR_AD_OPTION_BASIC || NASA_PRODUCT_OPTION || ||
0x0601 || STR_AD_OPTION_INSTALL || NASA_INSTALL_OPTION || ||
0x0602 || STR_AD_OPTION_INSTALL_2 || NASA_INSTALLOPTION2 || ||
0x0603 || STR_AD_OPTION_CYCLE || NASA_CYCLEOPTION || ||
0x0604 || || NASA_PBAOPTION || ||
0x0605 || STR_AD_INFO_EQUIP_POSITION || NASA_NAME || || appears when using S-NET pro 2 software
0x0607 || STR_AD_ID_SERIAL_NUMBER || NASA_SERIAL_NO || OutdoorTableSerialNumber ||
0x0608 || STR_AD_DBCODE_MICOM_MAIN || NASA_MICOM_CODE || OutdoorUnitMainDBCodeVersion || VariableAssign Identifier="dbCode"
0x060C || STR_AD_DBCODE_EEPROM || NASA_EEPROM_CODE || OutdoorTableEEPROMDBCodeVersion ||
0x0613 || || NASA_SIMPIM_SYNC_DATETIME || ||
0x0619 || || NASA_SIMPIM_PASSWORD || ||
0x061A || STR_AD_PRODUCT_MODEL_NAME || NASA_PRODUCT_MODEL_NAME || || appears when using S-NET pro 2 software
0x061C || STR_AD_PRODUCT_MAC_ADDRESS || || WiFi Kit MAC Address ||
0x061F || STR_AD_ID_MODEL_NAME || || Model Name || appears when using S-NET pro 2 software
0x2000 || || NASA_IM_MASTER || ||
0x2001 || || NASA_CHANGE_POLAR || ||
0x2002 || || NASA_ADDRESSING_ASSIGN_CONFIRM_ADDRESS || ||
0x2003 || || NASA_ADDRESSING || || seen in NASA data from EHS Mono HT Quiet
0x2004 || ENUM_NM_? || NASA_PNP || ||
0x2006 || || NASA_CHANGE_CONTROL_NETWORK_STATUS || ||
0x2007 || || NASA_CHANGE_SET_NETWORK_STATUS || ||
0x2008 || || NASA_CHANGE_LOCAL_NETWORK_STATUS || ||
0x2009 || || NASA_CHANGE_MODULE_NETWORK_STATUS || ||
0x200A || || NASA_CHANGE_ALL_NETWORK_STATUS || ||
0x200F || ENUM_NM_NETWORK_POSITINON_LAYER || NASA_LAYER || Enumeration Type ||
0x2010 || ENUM_NM_NETWORK_TRACKING_STATE || NASA_TRACKING_RESULT || ||
0x2012 || ENUM_NM_? || || || seen in NASA data from EHS Mono HT Quiet, following 0x2003
0x2015 || ENUM_NM_? || || || seen in NASA data from EHS Mono HT Quiet, following 0x2012
0x2017 || || NASA_COMMU_MICOM_LED || ||
0x2018 || || NASA_COMMU_MICOM_BUTTON || ||
0x20FF || ENUM_NM_? || || ||
0x22F7 || VAR_NM_?? || || || seen in NASA data from EHS Mono HT Quiet
0x22F8 || VAR_NM_?? || || || seen in NASA data from EHS Mono HT Quiet, following 0x0401 and 0x0403
0x22F9 || VAR_NM_?? || || ||
0x22FA || VAR_NM_?? || || || seen in NASA data from EHS Mono HT Quiet
0x22FB || VAR_NM_?? || || || seen in NASA data from EHS Mono HT Quiet
0x22FC || VAR_NM_?? || || || seen in NASA data from EHS Mono HT Quiet
0x22FD || VAR_NM_?? || || || seen in NASA data from EHS Mono HT Quiet
0x22FE || VAR_NM_?? || || || seen in NASA data from EHS Mono HT Quiet
0x22FF || VAR_NM_?? || || ||
0x2400 || LVAR_NM_?? || NASA_ALL_LAYER_DEVICE_COUNT || || seen in NASA data from EHS Mono HT Quiet
0x2401 || LVAR_NM_?? || || || seen in NASA data from EHS Mono HT Quiet
0x24FB || LVAR_NM_?? || || || seen in NASA data from EHS Mono HT Quiet
0x24FC || LVAR_NM_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4000 || ENUM_IN_OPERATION_POWER || NASA_POWER || Indoor unit power on/off || 0 Off, 1 On, 2 On
0x4001 || ENUM_IN_OPERATION_MODE || NASA_INDOOR_OPMODE || Indoor unit control mode || 0 Auto, 1 Cool, 2 Dry, 3 Fan, 4 Heat, 21 Cool Storage, 24 Hot water
0x4002 || ENUM_IN_OPERATION_MODE_REAL || NASA_INDOOR_REAL_OPMODE || Indoor unit current operation mode || 0 Auto, 1 Cool, 2 Dry, 3 Fan, 4 Heat, 11 Auto Cool, 12 Auto Dry, 13 Auto Fan, 14 Auto Heat, 21 Cool Storage, 24 Hot water, 255 NULL mode
0x4003 || ENUM_IN_OPERATION_VENT_POWER || NASA_ERV_POWER || Ventilation operation mode ||
0x4004 || ENUM_IN_OPERATION_VENT_MODE || NASA_ERV_OPMODE || ||
0x4006 || ENUM_IN_?? || NASA_FANSPEED || ||
0x4007 || ENUM_IN_FAN_MODE_REAL || || Indoor unit current air volume ||
0x4008 || ENUM_IN_FAN_VENT_MODE || NASA_ERV_FANSPEED || Indoor unit current air volume ||
0x400F || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4010 || ENUM_IN_?? || || ||
0x4011 || ENUM_IN_LOUVER_HL_SWING || NASA_AIRFLOW_UPDOWN || Up and down wind direction setting/status ||
0x4012 || ENUM_IN_LOUVER_HL_PART_SWING || || Up and down wind direction setting/status ||
0x4015 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4018 || ENUM_IN_?? || NASA_USE_WIREDREMOTE || ||
0x4019 || ENUM_IN_?? || NASA_USE_DISCHARGE_TEMP || This value is a value that cannot be controlled by the upper controller. ||
0x401B || ENUM_IN_?? || NASA_USE_CENTUAL_CONTROL || Income from InstallOption information. ||
0x4023 || ENUM_IN_?? || NASA_USE_SPI || ||
0x4024 || ENUM_IN_?? || NASA_USE_FILTER_WARNING_TIME || ||
0x4025 || || NASA_FILTER_CLEAN || ||
0x4027 || ENUM_IN_?? || NASA_FILTER_WARNING || ||
0x4028 || ENUM_IN_STATE_THERMO || || Thermo On/Off || 0 Off, 1 On
0x4029 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x402A || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x402B || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x402D || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x402E || ENUM_IN_STATE_DEFROST_MODE || NASA_INDOOR_DEFROST_STATUS || Defrost mode || 0 Off, 1 On
0x402F || ENUM_IN_MTFC || || ||
0x4031 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4035 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4038 || ENUM_IN_STATE_HUMIDITY_PERCENT || NASA_HUMIDITY_PERCENT || ||
0x403D || || NASA_CONTROL_OAINTAKE || ||
0x403E || || NASA_USE_MDS || ||
0x403F || || NASA_CONTROL_MDS || ||
0x4040 || || NASA_USE_HUMIDIFICATION || ||
0x4041 || || NASA_CONTROL_HUMIDIFICATION || ||
0x4042 || || NASA_CONTROL_AUTO_CLEAN || ||
0x4043 || ENUM_IN_?? || NASA_CONTROL_SPI || ||
0x4045 || || NASA_USE_SILENCE || ||
0x4046 || ENUM_IN_SILENCE || NASA_CONTROL_SILENCE || Silence mode || 0 Off, 1 On
0x4047 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4048 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x404F || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4050 || || NASA_CONTROL_SILENCT || ||
0x4051 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4059 || ENUM_IN_?? || || ||
0x405B || || NASA_USE_OUTER_COOL || ||
0x405C || || NASA_CONTROL_OUTER_COOL || ||
0x405D || || NASA_USE_DESIRED_HUMIDITY || ||
0x405E || || NASA_CONTROL_DESIRED_HUMIDITY || ||
0x405F || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4060 || ENUM_IN_ALTERNATIVE_MODE || NASA_ALTERNATIVE_MODE || || 0 Off, 9 On
0x4063 || || NASA_EHS_INDOOR_POWER || ||
0x4064 || || NASA_EHS_INDOOR_OPMODE || ||
0x4065 || ENUM_IN_WATER_HEATER_POWER || NASA_DHW_POWER || Water heater power || 0 Off, 1 On
0x4066 || ENUM_IN_WATER_HEATER_MODE || NASA_DHW_OPMODE || Water heater mode || 0 Eco, 1 Standard, 2 Power, 3 Force
0x4067 || ENUM_IN_3WAY_VALVE || NASA_DHW_VALVE || Hydro_3Way || 0 Room, 1 Tank
0x4068 || ENUM_IN_SOLAR_PUMP || NASA_SOLAR_PUMP || Hydro_SolarPump ||
0x4069 || ENUM_IN_THERMOSTAT1 || || Hydro_ExternalThermostat || 0 Off, 1 Cool, 2 Heat
0x406A || ENUM_IN_THERMOSTAT2 || || Hydro_ExternalThermostat2 || 0 Off, 1 Cool, 2 Heat
0x406B || ENUM_IN_?? || NASA_SMART_GRID || ||
0x406C || ENUM_IN_BACKUP_HEATER || || Backup heater mode || 0 Off, 1 Step 1, 2 Step 2
0x406D || ENUM_IN_OUTING_MODE || NASA_INDOOR_OUT_GOING || Outing mode || 0 Off, 1 On
0x406E || ENUM_IN_QUIET_MODE || || ||
0x406F || ENUM_IN_REFERENCE_EHS_TEMP || NASA_DHW_REFERENCE_TEMP || Hydro_ControlChoice_RoomTemp || 0 Room, 1 Water out. Variable isEhsSetTempWaterOut. See 0x4201 and 0x4247.
0x4070 || ENUM_IN_DISCHAGE_TEMP_CONTROL || NASA_DISCHARGE_TEMP_ENABLE || || 0 Off, 1 On (rem: "DISCHAGE" is typo in NASA.ptc)
0x4073 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4074 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4076 || ENUM_IN_ROOM_TEMP_SENSOR || || || It tells the room sensor is present for zone #1 (EHS Mono R290 AE050CXYBEK).
0x4077 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x407B || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x407D || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x407E || ENUM_IN_LOUVER_LR_SWING || NASA_AIRFLOW_LEFTRIGHT || Left and right wind direction settings/status || 0 Off, 1 On
0x4085 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4086 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4087 || ENUM_IN_BOOSTER_HEATER || || Booster heater || 0 Off, 1 On
0x4089 || ENUM_IN_STATE_WATER_PUMP || || Water pump || 0 Off, 1 On
0x408A || ENUM_IN_2WAY_VALVE || || || 0 Off, 2 CV, 3 Boiler
0x4093 || ENUM_IN_FSV_2041 || || FSV Water Law Type Heating || 1 Floor, 2 FCU
0x4094 || ENUM_IN_FSV_2081 || || FSV Water Law Type Cooling || 1 Floor, 2 FCU
0x4095 || ENUM_IN_FSV_2091 || NASA_USE_THERMOSTAT1 || || values 0="No" up to 4="4"
0x4096 || ENUM_IN_FSV_2092 || NASA_USE_THERMOSTAT2 || || values 0="No" up to 4="4"
0x4097 || ENUM_IN_FSV_3011 || NASA_ENABLE_DHW || || values 0="No" up to 2="2"
0x4098 || ENUM_IN_FSV_3031 || NASA_USE_BOOSTER_HEATER || || 0 Off, 1 On
0x4099 || ENUM_IN_FSV_3041 || || || 0 No, 1 Yes
0x409A || ENUM_IN_FSV_3042 || || || Sunday=0, Monday=1 .. up to 7=Everyday
0x409B || ENUM_IN_FSV_3051 || || || 0 No, 1 Yes
0x409C || ENUM_IN_FSV_3061 || NASA_USE_DHW_THERMOSTAT || ||
0x409D || ENUM_IN_FSV_3071 || || ||
0x409E || ENUM_IN_FSV_4011 || || ||
0x409F || ENUM_IN_FSV_4021 || || ||
0x40A0 || ENUM_IN_FSV_4022 || || ||
0x40A1 || ENUM_IN_FSV_4023 || || ||
0x40A2 || ENUM_IN_FSV_4031 || || ||
0x40A3 || ENUM_IN_FSV_4032 || || ||
0x40A4 || ENUM_IN_FSV_5041 || || ||
0x40A5 || ENUM_IN_FSV_5042 || || ||
0x40A6 || ENUM_IN_FSV_5043 || || ||
0x40A7 || ENUM_IN_FSV_5051 || || ||
0x40B1 || || NASA_DHW_OPMODE_SUPPORT || ||
0x40B4 || ENUM_IN_FSV_5061 || || ||
0x40B5 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x40BB || ENUM_IN_STATE_AUTO_STATIC_PRESSURE_RUNNING || || ||
0x40BC || ENUM_IN_STATE_KEY_TAG || NASA_VACANCY_STATUS || Vacancy control ||
0x40BD || ENUM_IN_EMPTY_ROOM_CONTROL_USED || NASA_USE_VACANCY_STATUS || ||
0x40C0 || ENUM_IN_FSV_4041 || || ||
0x40C1 || ENUM_IN_FSV_4044 || || ||
0x40C2 || ENUM_IN_FSV_4051 || || ||
0x40C3 || ENUM_IN_FSV_4053 || || ||
0x40C4 || ENUM_IN_WATERPUMP_PWM_VALUE || || Water pump speed || unit %
0x40C5 || ENUM_IN_THERMOSTAT_WATER_HEATER || || Hydro_WaterHeaterThermostat ||
0x40C6 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x40C7 || || NASA_AHUPANEL_ENTHALPY_CONTROL || ||
0x40C8 || || NASA_AHUPANEL_DUTY_CONTROL || ||
0x40C9 || || NASA_AHUPANEL_SUMMERNIGHT_CONTROL || ||
0x40CA || || NASA_AHUPANEL_CO2_CONTROL || ||
0x40CB || || NASA_AHUPANEL_ENERGYMANAGE_CONTROL || ||
0x40CC || || NASA_AHUPANEL_RA_SMOKE_DECTION_STATUS || ||
0x40CD || || NASA_AHUPANEL_SA_FAN_STATUS || ||
0x40CE || || NASA_AHUPANEL_RA_FAN_ONOFF_STATUS || ||
0x40CF || || NASA_AHUPANEL_ERROR_STATUS || ||
0x40D0 || || NASA_AHUPANEL_HEATER_ONOFF_STATUS || ||
0x40D1 || || NASA_AHUPANEL_SA_FAN_ONOFF_STATUS || ||
0x40D2 || || NASA_AHUPANEL_SMOKE_DECTION_CONTROL || ||
0x40D5 || ENUM_IN_ENTER_ROOM_CONTROL_USED || || ||
0x40D6 || ENUM_IN_ERROR_HISTORY_CLEAR_FOR_HASS || || ||
0x40E3 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x40E7 || ENUM_IN_CHILLER_WATERLAW_SENSOR || || DMV Chiller Option ||
0x40F7 || ENUM_IN_CHILLER_WATERLAW_ON_OFF || || ||
0x40FB || ENUM_IN_CHILLLER_SETTING_SILENT_LEVEL || || ||
0x40FC || ENUM_IN_CHILLER_SETTING_DEMAND_LEVEL || || ||
0x4101 || ENUM_IN_CHILLER_EXT_WATER_OUT_INPUT || || ||
0x4102 || ENUM_IN_STATE_FLOW_CHECK || || ||
0x4103 || ENUM_IN_WATER_VALVE_1_ON_OFF || || FCU Kit ||
0x4104 || ENUM_IN_WATER_VALVE_2_ON_OFF || || ||
0x4105 || ENUM_IN_ENTHALPY_CONTROL_STATE || || ||
0x4107 || ENUM_IN_FSV_5033 || || ||
0x4108 || ENUM_IN_TDM_INDOOR_TYPE || || ||
0x410D || ENUM_IN_FREE_COOLING_STATE || || ||
0x4113 || ENUM_IN_3WAY_VALVE_2 || || ||
0x4117 || ENUM_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4118 || ENUM_IN_ROOM_TEMP_SENSOR_ZONE2 || || || It tells the room sensor is present for zone #2 (EHS Mono R290 AE050CXYBEK).
0x4119 || ENUM_IN_OPERATION_POWER_ZONE1 || || ||
0x411A || ENUM_IN_FSV_4061 || || ||
0x411B || ENUM_IN_FSV_5081 || || ||
0x411C || ENUM_IN_FSV_5091 || || ||
0x411D || ENUM_IN_FSV_5094 || || ||
0x411E || ENUM_IN_OPERATION_POWER_ZONE2 || || Zone2 Normal Power || Min = 0 Max = 1
0x4123 || ENUM_IN_PV_CONTACT_STATE || || PV Control ||
0x4124 || ENUM_IN_SG_READY_MODE_STATE || || Smart Grid ||
0x4125 || ENUM_IN_FSV_LOAD_SAVE || || || Min = 0 Max = 1, similar name as 0x412D in NASA.ptc
0x4127 || ENUM_IN_FSV_2093 || || || Min = 1 Max = 4
0x4128 || ENUM_IN_FSV_5022 || || || Min = 0 Max = 1
0x412A || ENUM_IN_FSV_2094 || || || values 0="No" up to 4="4"
0x412D || ENUM_IN_FSV_LOAD_SAVE || || || Min = 0 Max = 1, similar name as 0x4125 in NASA.ptc
0x4147 || ENUM_IN_GAS_LEVEL || || ||
0x4149 || ENUM_IN_DIFFUSER_OPERATION_POWER || || ||
0x4201 || VAR_IN_TEMP_TARGET_F || NASA_SET_TEMP || Indoor unit set temperature || if isEhsSetTempWaterOut (406F) ==1 , use value of variable waterOutSetTemp = 4247
0x4202 || VAR_IN_?? || || ||
0x4203 || VAR_IN_TEMP_ROOM_F || NASA_CURRENT_TEMP || Room Temperature || Room temperature for zone #1
0x4204 || VAR_IN_?? || NASA_MODIFIED_CURRENT_TEMP || Temperature ||
0x4205 || VAR_IN_TEMP_EVA_IN_F || NASA_EVA_IN_TEMP || Indoor Eva In Temperature ||
0x4206 || VAR_IN_TEMP_EVA_OUT_F || NASA_EVA_OUT_TEMP || Indoor Eva Out Temperature ||
0x4207 || VAR_IN_TEMP_ELECTRIC_HEATER_F || || Electric heater temperature value ||
0x4208 || || NASA_EVA_INHOLE_TEMP || ||
0x4209 || VAR_IN_?? || NASA_SET_DISCHARGE || ||
0x420B || VAR_IN_TEMP_DISCHARGE || NASA_CURRENT_DISCHARGE || Indoor Discharge Temp(Duct, AHU) ||
0x420C || VAR_IN_?? || NASA_INDOOR_OUTER_TEMP || || same value as 0x8204 (sensor_airout) ?
0x4211 || VAR_IN_CAPACITY_REQUEST || NASA_INDOOR_CAPACITY || Capacity ||
0x4212 || VAR_IN_CAPACITY_ABSOLUTE || NASA_INDOOR_ABSOLUTE_CAPACITY || ||
0x4213 || VAR_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4217 || VAR_IN_EEV_VALUE_REAL_1 || NASA_INODDR_CURRENT_EEV1 || Current EEV development level ||
0x4218 || VAR_IN_EEV_VALUE_REAL_2 || NASA_INDOOR_CURRENT_EEV2 || Current EEV2 development level ||
0x4219 || VAR_IN_?? || NASA_INDOOR_CURRENT_EEV3 || ||
0x421A || || NASA_INDOOR_CURRENT_EEV4 || ||
0x421B || VAR_IN_SENSOR_CO2_PPM || || CO2 sensor detection ppm ||
0x4220 || || NASA_INDOOR_AIRCLEANFAN_CURRENT_RPM || ||
0x4229 || VAR_IN_MODEL_INFORMATION || NASA_INDOOR_MODEL_INFORMATION || Indoor unit model information ||
0x422A || VAR_IN_TEMP_DISCHARGE_COOL_TARGET_F || NASA_COOL_SET_DISCHARGE || User limitation - Water Cooling Temperature Max. ||
0x422B || VAR_IN_TEMP_DISCHARGE_HEAT_TARGET_F || NASA_HEAT_SET_DISCHARGE || ||
0x4235 || VAR_IN_TEMP_WATER_HEATER_TARGET_F || NASA_INDOOR_DHW_SET_TEMP || DHW target temperature ||
0x4236 || VAR_IN_TEMP_WATER_IN_F || NASA_INDOOR_WATER_IN_TEMP || Hydro_WaterIn ||
0x4237 || VAR_IN_TEMP_WATER_TANK_F || NASA_INDOOR_DHW_CURRENT_TEMP || DHW tank current temperature ||
0x4238 || VAR_IN_TEMP_WATER_OUT_F || NASA_INDOOR_WATER_OUT_TEMP || Hydro_WaterOut ||
0x4239 || VAR_IN_TEMP_WATER_OUT2_F || || Hydro_HeaterOut ||
0x423E || VAR_IN_?? || || ||
0x4247 || VAR_IN_TEMP_WATER_OUTLET_TARGET_F || NASA_INDOOR_SETTEMP_WATEROUT || Hydro_WaterOutletTargetF || variable waterOutSetTemp
0x4248 || VAR_IN_TEMP_WATER_LAW_TARGET_F || || ||
0x424A || VAR_IN_FSV_1011 || NASA_INDOOR_COOL_MAX_SETTEMP_WATEROUT || User limitation - Water Cooling Temperature Max. ||
0x424B || VAR_IN_FSV_1012 || NASA_INDOOR_COOL_MIN_SETTEMP_WATEROUT || ||
0x424C || VAR_IN_FSV_1021 || NASA_INDOOR_COOL_MAX_SETTEMP_ROOM || User limitation - Room Cooling Temperature Max. ||
0x424D || VAR_IN_FSV_1022 || NASA_INDOOR_COOL_MIN_SETTEMP_ROOM || ||
0x424E || VAR_IN_FSV_1031 || NASA_INDOOR_HEAT_MAX_SETTEMP_WATEROUT || User limitation - Water Heating Temperature Max. ||
0x424F || VAR_IN_FSV_1032 || NASA_INDOOR_HEAT_MIN_SETTEMP_WATEROUT || ||
0x4250 || VAR_IN_FSV_1041 || NASA_INDOOR_HEAT_MAX_SETTEMP_ROOM || User limitation - Room heating Temperature Max. ||
0x4251 || VAR_IN_FSV_1042 || NASA_INDOOR_HEAT_MIN_SETTEMP_ROOM || ||
0x4252 || VAR_IN_FSV_1051 || NASA_DHW_MAX_SETTEMPLIMIT || User limitation - Hot Water Temperature Max. ||
0x4253 || VAR_IN_FSV_1052 || NASA_DHW_MIN_SETTEMPLIMIT || ||
0x4254 || VAR_IN_FSV_2011 || || Water Law Auto heating ambient temperature - Max. ||
0x4255 || VAR_IN_FSV_2012 || || ||
0x4256 || VAR_IN_FSV_2021 || || Water Law (WL1-Floor) Temperature auto heating - Max. ||
0x4257 || VAR_IN_FSV_2022 || || ||
0x4258 || VAR_IN_FSV_2031 || || Water Law (WL2-FCU) Temperature auto heating - Max. ||
0x4259 || VAR_IN_FSV_2032 || || ||
0x425A || VAR_IN_FSV_2051 || || ||
0x425B || VAR_IN_FSV_2052 || || ||
0x425C || VAR_IN_FSV_2061 || || ||
0x425D || VAR_IN_FSV_2062 || || ||
0x425E || VAR_IN_FSV_2071 || || ||
0x425F || VAR_IN_FSV_2072 || || ||
0x4260 || VAR_IN_FSV_3021 || || DHW Heating mode - Max. ||
0x4261 || VAR_IN_FSV_3022 || || ||
0x4262 || VAR_IN_FSV_3023 || || DHW Heating mode - Start ||
0x4263 || VAR_IN_FSV_3024 || || ||
0x4264 || VAR_IN_FSV_3025 || || DHW Heating mode - DHW operation time ||
0x4265 || VAR_IN_FSV_3026 || || ||
0x4266 || VAR_IN_FSV_3032 || || DHW Booster heater - Delayed time ||
0x4267 || VAR_IN_FSV_3033 || || ||
0x4268 || VAR_IN_FSV_3034 || || || not for EHS Mono HT Quiet
0x4269 || VAR_IN_FSV_3043 || || ||
0x426A || VAR_IN_FSV_3044 || || Desinfection - Target temp. ||
0x426B || VAR_IN_FSV_3045 || || ||
0x426C || VAR_IN_FSV_3052 || || ||
0x426D || VAR_IN_FSV_4012 || || ||
0x426E || VAR_IN_FSV_4013 || || Heating mode - Heating Off ||
0x426F || VAR_IN_FSV_4014 || || ||
0x4270 || VAR_IN_FSV_4024 || || ||
0x4271 || VAR_IN_FSV_4025 || || ||
0x4272 || VAR_IN_FSV_4033 || || ||
0x4273 || VAR_IN_FSV_5011 || || ||
0x4274 || VAR_IN_FSV_5012 || || Outing mode - Room Temperature of cooling Mode ||
0x4275 || VAR_IN_FSV_5013 || || ||
0x4276 || VAR_IN_FSV_5014 || || Outing mode- Indoor heating temperature ||
0x4277 || VAR_IN_FSV_5015 || || ||
0x4278 || VAR_IN_FSV_5016 || || ||
0x4279 || VAR_IN_FSV_5017 || || ||
0x427A || VAR_IN_FSV_5018 || || Outing mode - Temperature of auto heating WL2 water ||
0x427B || VAR_IN_FSV_5019 || || ||
0x427C || VAR_IN_FSV_5021 || || Economic DHW mode - Temperature of hot water Tank ||
0x427D || VAR_IN_FSV_5031 || || ||
0x427E || VAR_IN_FSV_5032 || || ||
0x427F || VAR_IN_TEMP_WATER_LAW_F || || Hydro_WaterLawTargetF ||
0x4284 || VAR_IN_?? || NASA_INDOOR_POWER_CONSUMPTION || Indoor unit power consumption ||
0x4286 || VAR_IN_FSV_4042 || || ||
0x4287 || VAR_IN_FSV_4043 || || ||
0x4288 || VAR_IN_FSV_4045 || || ||
0x4289 || VAR_IN_FSV_4046 || || ||
0x428A || VAR_IN_FSV_4052 || || ||
0x428C || VAR_IN_TEMP_MIXING_VALVE_F || || Hydro_MixingValve ||
0x428D || VAR_IN_?? || || || seen in NASA data from EHS Mono HT Quiet
0x4290 || VAR_IN_?? || NASA_AHUPANEL_TARGET_HUMIDITY || ||
0x4291 || || NASA_AHUPANEL_OA_DAMPER_TARGET_RATE || ||
0x4292 || VAR_IN_?? || NASA_AHUPANEL_RA_TEMP || ||
0x4293 || || NASA_AHUPANEL_RA_HUMIDITY || ||
0x4294 || VAR_IN_?? || NASA_AHUPANEL_EA_RATE || ||
0x4295 || || NASA_AHUPANEL_OA_TEMP || ||
0x4296 || VAR_IN_?? || NASA_AHUPANEL_OA_HUMIDITY || ||
0x4297 || VAR_AHU_PANEL_SA_TEMP || NASA_AHUPANEL_SA_TEMP || ||
0x4298 || VAR_AHU_PANEL_SA_HUMIDITY || NASA_AHUPANEL_SA_HUMIDITY || ||
0x4299 || || NASA_AHUPANEL_STATIC_PRESSURE || ||
0x429A || VAR_IN_?? || NASA_AHUPANEL_MIXING_TEMP || ||
0x429B || || NASA_AHUPANEL_MIXING_RATE || ||
0x429C || VAR_IN_?? || NASA_AHUPANEL_POINT_STATUS || ||
0x429F || VAR_IN_FAN_CURRENT_RPM_SUCTION1 || || ||
0x42A1 || VAR_IN_FAN_CURRENT_RPM_SUCTION2 || || ||
0x42A3 || VAR_IN_FAN_CURRENT_RPM_SUCTION3 || || ||
0x42A5 || VAR_IN_TEMP_PANEL_AIR_COOL1_F || || ||
0x42A6 || VAR_IN_TEMP_PANEL_AIR_COOL2_F || || ||
0x42A7 || VAR_IN_TEMP_PANEL_ROOM_COOL1_F || || ||
0x42A8 || VAR_IN_TEMP_PANEL_ROOM_COOL2_F || || ||
0x42A9 || VAR_IN_TEMP_PANEL_TARGET_COOL1_F || || ||
0x42AA || VAR_IN_TEMP_PANEL_TARGET_COOL2_F || || ||
0x42AB || VAR_IN_TEMP_PANEL_AIR_HEAT1_F || || ||
0x42AC || VAR_IN_TEMP_PANEL_AIR_HEAT2_F || || ||
0x42AD || VAR_IN_TEMP_PANEL_ROOM_HEAT1_F || || ||
0x42AE || VAR_IN_TEMP_PANEL_ROOM_HEAT2_F || || ||
0x42AF || VAR_IN_TEMP_PANEL_TARGET_HEAT1_F || || ||
0x42B0 || VAR_IN_TEMP_PANEL_TARGET_HEAT2_F || || ||
0x42B1 || VAR_IN_MCC_GROUP_MODULE_ADDRESS || || ||
0x42B2 || VAR_IN_MCC_GROUP_MAIN || || ||
0x42B3 || VAR_IN_MCC_MODULE_MAIN || || ||
0x42C2 || VAR_IN_TEMP_EVA2_IN_F || || Indoor Eva2 In temperature ||
0x42C3 || VAR_IN_TEMP_EVA2_OUT_F || || Indoor Eva2 Out Temperature ||
0x42C4 || VAR_IN_CHILLER_PHE_IN_P || || Inlet pressure ||
0x42C5 || VAR_IN_CHILLER_PHE_OUT_P || || Outlet pressure ||
0x42C9 || VAR_IN_CHILLER_EXTERNAL_TEMPERATURE || || External sensor-Room temperature ||
0x42CA || VAR_IN_MODULATING_VALVE_1 || || ||
0x42CB || VAR_IN_MODULATING_VALVE_2 || || ||
0x42CC || VAR_IN_MODULATING_FAN || || ||
0x42CD || VAR_IN_TEMP_WATER_IN2_F || || ||
0x42CE || VAR_IN_FSV_3046 || || DHW Desinfection - Max. operation time || NASA Value is [minutes], not [hours]
0x42CF || VAR_IN_ENTHALPY_SENSOR_OUTPUT || || ||
0x42D0 || VAR_IN_EXT_VARIABLE_DAMPER_OUTPUT || || ||
0x42D1 || VAR_IN_DUST_SENSOR_PM10_0_VALUE || || ||
0x42D2 || VAR_IN_DUST_SENSOR_PM2_5_VALUE || || ||
0x42D3 || VAR_IN_DUST_SENSOR_PM1_0_VALUE || || ||
0x42D4 || VAR_IN_TEMP_ZONE2_F || || Idiom_RoomTemp_Zone2 || Room temperature for zone #2
0x42D6 || VAR_IN_TEMP_TARGET_ZONE2_F || || Zone2 Room Set Temp. ||
0x42D7 || VAR_IN_TEMP_WATER_OUTLET_TARGET_ZONE2_F || || Water Outlet2 Set Temp. ||
0x42D8 || VAR_IN_TEMP_WATER_OUTLET_ZONE1_F || || Zone1 WaterOut Temp ||
0x42D9 || VAR_IN_TEMP_WATER_OUTLET_ZONE2_F || || Zone2 WaterOut Temp ||
0x42DB || VAR_IN_FSV_5082 || || ||
0x42DC || VAR_IN_FSV_5083 || || ||
0x42DD || VAR_IN_FSV_5092 || || ||
0x42DE || VAR_IN_FSV_5093 || || ||
0x42E8 || VAR_IN_FLOW_SENSOR_VOLTAGE || || ||
0x42E9 || VAR_IN_FLOW_SENSOR_CALC || || Flow Sensor || value appears about every 90 seconds
0x42ED || VAR_IN_FSV_3081 || || ||
0x42EE || VAR_IN_FSV_3082 || || ||
0x42EF || VAR_IN_FSV_3083 || || ||
0x42F0 || VAR_IN_FSV_5023 || || ||
0x42F1 || VAR_OUT_COMP_FREQ_RATE_CONTROL || || || undocumented, taken from Pyton code
0x4301 || VAR_IN_?? || || ||
0x4302 || VAR_IN_CAPACITY_VENTILATION_REQUEST || || ||
0x4401 || LVAR_IN_?? || || ||
0x4405 || || NASA_GROUPCONTROL_BIT1 || ||
0x4406 || || NASA_GROUPCONTROL_BIT2 || ||
0x4407 || || NASA_GROUPCONTROL_BIT3 || ||
0x440A || LVAR_IN_DEVICE_STAUS_HEATPUMP_BOILER || || Switch_HyrdoFlow ||
0x440E || LVAR_IN_?? || || ||
0x440F || LVAR_IN_?? || NASA_ERROR_INOUT || ||
0x4415 || LVAR_IN_AUTO_STATIC_PRESSURE || || ||
0x4418 || LVAR_IN_EMPTY_ROOM_CONTROL_DATA || NASA_VACANCY_SETTING || ||
0x441B || LVAR_IN_ENTER_ROOM_CONTROL_DATA || || ||
0x441F || LVAR_IN_ETO_COOL_CONTROL_DATA || || ||
0x4420 || LVAR_IN_ETO_HEAT_CONTROL_DATA || || ||
0x4423 || LVAR_IN_?? || || Minutes since installation || seen in NASA data from EHS Mono HT Quiet
0x4424 || LVAR_IN_?? || || Minutes active || seen in NASA data from EHS Mono HT Quiet
0x4426 || LVAR_IN_?? || || Generated power last minute ||
0x4427 || LVAR_IN_?? || || Total generated power ||
0x4604 || STR_IN_INSTALL_INDOOR_SETUP_INFO || NASA_INDOOR_ABLE_FUNCTION || ||
0x4608 || || NASA_INDOOR_SETTING_MIN_MAX_TEMP || ||
0x4612 || STR_IN_?? || NASA_?? || Source_Adress_Class: WiFiKit || seen in NASA data from EHS Mono HT Quiet
0x4619 || || NASA_EHS_SETTING_MIN_MAX_TEMP || ||
0x461A || || NASA_EHS_FSV_SETTING_MIN_MAX_TEMP || ||
0x461C || || NASA_AHUPANEL_AHUKIT_ADDRESS || ||
0x461D || || NASA_AHUPANEL_PANEL_OPTION || ||
0x461E || STR_IN_ERROR_HISTORY_FOR_HASS || || Structure Type ||
0x8000 || ENUM_OUT_OPERATION_SERVICE_OP || || Indoor unit defrost operation steps || 2 Heating test run, 3 Pump out, 13 Cooling test run, 14 Pump down
0x8001 || ENUM_OUT_OPERATION_ODU_MODE || NASA_OUTDOOR_OPERATION_STATUS || Outdoor Driving Mode || 0 OP_STOP, 1 OP_SAFETY, 2 OP_NORMAL, 3 OP_BALANCE, 4 OP_RECOVERY, 5 OP_DEICE, 6 OP_COMPDOWN, 7 OP_PROHIBIT, 8 OP_LINEJIG, 9 OP_PCBJIG, 10 OP_TEST, 11 OP_CHARGE, 12 OP_PUMPDOWN, 13 OP_PUMPOUT, 14 OP_VACCUM, 15 OP_CALORYJIG, 16 OP_PUMPDOWNSTOP, 17 OP_SUBSTOP, 18 OP_CHECKPIPE, 19 OP_CHECKREF, 20 OP_FPTJIG, 21 OP_NONSTOP_HEAT_COOL_CHANGE, 22 OP_AUTO_INSPECT, 23 OP_ELECTRIC_DISCHARGE, 24 OP_SPLIT_DEICE, 25 OP_INVETER_CHECK, 26 OP_NONSTOP_DEICE, 27 OP_REM_TEST, 28 OP_RATING, 29 OP_PC_TEST, 30 OP_PUMPDOWN_THERMOOFF, 31 OP_3PHASE_TEST, 32 OP_SMARTINSTALL_TEST, 33 OP_DEICE_PERFORMANCE_TEST, 34 OP_INVERTER_FAN_PBA_CHECK, 35 OP_AUTO_PIPE_PAIRING, 36 OP_AUTO_CHARGE
0x8002 || ENUM_OUT_?? || || ||
0x8003 || ENUM_OUT_OPERATION_HEATCOOL || NASA_OUTDOOR_OPERATION_MODE || Outdoor unit cooling/heating mode || 1 Cool, 2 Heat, 3 CoolMain, 4 HeatMain
0x8005 || ENUM_OUT_?? || || ||
0x800D || ENUM_OUT_?? || || ||
0x8010 || ENUM_OUT_LOAD_COMP1 || NASA_OUTDOOR_COMP1_STATUS || Comp#1 On/Off ||
0x8011 || ENUM_OUT_LOAD_COMP2 || NASA_OUTDOOR_COMP2_STATUS || Comp#2 On/Off ||
0x8012 || ENUM_OUT_LOAD_COMP3 || NASA_OUTDOOR_COMP3_STATUS || Comp#3 On/Off ||
0x8013 || ENUM_OUT_LOAD_CCH1 || NASA_OUTDOOR_CCH1_STATUS || CCH1 On/Off ||
0x8014 || ENUM_OUT_LOAD_CCH2 || NASA_OUTDOOR_CCH2_STATUS || CCH2 On/Off ||
0x8015 || || NASA_OUTDOOR_CCH3_STATUS || ||
0x8016 || || NASA_OUTDOOR_ACCUMULATOR_CCH || ||
0x8017 || ENUM_OUT_LOAD_HOTGAS || NASA_OUTDOOR_HOTGAS1 || HotGas1 On/Off ||
0x8018 || ENUM_OUT_LOAD_HOTGAS2 || NASA_OUTDOOR_HOTGAS2 || HotGas2 On/Off ||
0x8019 || ENUM_OUT_LOAD_LIQUID || NASA_OUTDOOR_LIQUID_BYPASS_VALVE || Liquid On/Off ||
0x801A || ENUM_OUT_LOAD_4WAY || NASA_OUTDOOR_4WAY_VALVE || 4Way On/Off ||
0x801F || ENUM_OUT_LOAD_MAINCOOL || NASA_OUTDOOR_MAIN_COOL_VALVE || ||
0x8020 || ENUM_OUT_LOAD_OUTEEV || NASA_OUTDOOR_OD_EEV_VALVE || ||
0x8021 || ENUM_OUT_LOAD_EVI_BYPASS || NASA_OUTDOOR_EVI_BYPASS_VALVE || EVI ByPass On/Off ||
0x8022 || ENUM_OUT_LOAD_EVI_SOL1 || NASA_OUTDOOR_EVI_SOL1_VALVE || EVI Sol1 On/Off ||
0x8023 || ENUM_OUT_LOAD_EVI_SOL2 || NASA_OUTDOOR_EVI_SOL2_VALVE || EVI Sol2 On/Off ||
0x8024 || || NASA_OUTDOOR_EVI_SOL3_VALVE || ||
0x8025 || ENUM_OUT_LOAD_GASCHARGE || NASA_OUTDOOR_GAS_CHARGE || Hot Gas Charging ||
0x8026 || ENUM_OUT_LOAD_WATER || NASA_OUTDOOR_WATER_VALVE || 2Way Valve ||
0x8027 || ENUM_OUT_LOAD_PUMPOUT || NASA_OUTDOOR_PUMPOUT_VALVE || Pump Out ||
0x802A || ENUM_OUT_LOAD_4WAY2 || NASA_OUTDOOR_4WAY2_VALVE || ||
0x8031 || ENUM_OUT_?? || || ||
0x8032 || ENUM_OUT_?? || || ||
0x8033 || ENUM_OUT_?? || || ||
0x8034 || ENUM_OUT_LOAD_LIQUIDTUBE || NASA_OUTDOOR_LIQUID_TUBE_VALVE || Liquid tube ||
0x8037 || ENUM_OUT_LOAD_ACCRETURN || NASA_OUTDOOR_ACCUM_RETURN_VALVE || ARV On/Off ||
0x803B || ENUM_OUT_LOAD_FLOW_SWITCH || NASA_OUTDOOR_FLOW_SWITCH || Flow Switch ||
0x803C || ENUM_OUT_OPERATION_AUTO_INSPECT_STEP || || Automatic check step ||
0x803F || ENUM_OUT_?? || || ||
0x8043 || ENUM_OUT_?? || || ||
0x8045 || ENUM_OUT_?? || || ||
0x8046 || ENUM_OUT_OP_TEST_OP_COMPLETE || NASA_OUTDOOR_TEST_OP_COMPLETE || ||
0x8047 || ENUM_OUT_?? || NASA_OUTDOOR_SERVICEOPERATION || ||
0x8048 || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x8049 || ENUM_OUT_MCU_LOAD_COOL_A || || MCU ||
0x804A || ENUM_OUT_MCU_LOAD_HEAT_A || || ||
0x804B || ENUM_OUT_MCU_LOAD_COOL_B || || ||
0x804C || ENUM_OUT_MCU_LOAD_HEAT_B || || ||
0x804D || ENUM_OUT_MCU_LOAD_COOL_C || || ||
0x804E || ENUM_OUT_MCU_LOAD_HEAT_C || || ||
0x804F || ENUM_OUT_MCU_LOAD_COOL_D || || ||
0x8050 || ENUM_OUT_MCU_LOAD_HEAT_D || || ||
0x8051 || ENUM_OUT_MCU_LOAD_COOL_E || || ||
0x8052 || ENUM_OUT_MCU_LOAD_HEAT_E || || ||
0x8053 || ENUM_OUT_MCU_LOAD_COOL_F || || ||
0x8054 || ENUM_OUT_MCU_LOAD_HEAT_F || || ||
0x8055 || ENUM_OUT_MCU_LOAD_LIQUID || || ||
0x8058 || ENUM_OUT_MCU_PORT0_INDOOR_ADDR || || ||
0x8059 || ENUM_OUT_MCU_PORT1_INDOOR_ADDR || || ||
0x805A || ENUM_OUT_MCU_PORT2_INDOOR_ADDR || || ||
0x805B || ENUM_OUT_MCU_PORT3_INDOOR_ADDR || || ||
0x805C || ENUM_OUT_MCU_PORT4_INDOOR_ADDR || || ||
0x805D || ENUM_OUT_MCU_PORT5_INDOOR_ADDR || || ||
0x805E || ENUM_OUT_?? || || ||
0x8061 || ENUM_OUT_DEICE_STEP_INDOOR || NASA_OUTDOOR_INDOOR_DEFROST_STEP || Indoor unit defrost operation steps || 1 Defrost stage 1, 2 Defrost stage 2, 3 Defrost stage 3, 7 Defrost operation end stage, 255 No defrost operation
0x8062 || || NASA_OUTDOOR_LOGICAL_DEFROST_STEP || ||
0x8063 || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x8065 || || NASA_OUTDOOR_SYSTEM_RESET || ||
0x8066 || ENUM_OUT_?? || NASA_OUTDOOR_OPMODELIMIT || || seen in NASA data from EHS Mono HT Quiet
0x8077 || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x8078 || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x8079 || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x807A || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x807B || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x807C || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x807D || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x807E || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x807F || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x8081 || ENUM_OUT_?? || NASA_OUTDOOR_EXT_CMD_OPERATION || || seen in NASA data from EHS Mono HT Quiet
0x8083 || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x808C || ENUM_OUT_?? || || ||
0x808D || ENUM_OUT_?? || || ||
0x808E || ENUM_OUT_OP_CHECK_REF_STEP || || Refrigerant amount level || This is Enum in definition. But we need operation, so just consider this as variable. Min = 0, Max = 8
0x808F || ENUM_OUT_?? || || ||
0x8092 || ENUM_OUT_INSTALL_ODU_COUNT || || ||
0x8099 || ENUM_OUT_CONTROL_FAN_NUM || || Number of outdoor fans ||
0x809C || ENUM_OUT_CHECK_REF_RESULT || || Refrigerant amount determination result ||
0x809D || ENUM_OUT_?? || NASA_OUTDOOR_COOLONLY_MODEL || || seen in NASA data from EHS Mono HT Quiet (value always = 0)
0x809E || ENUM_OUT_LOAD_CBOX_COOLING_FAN || NASA_OUTDOOR_CBOX_COOLING_FAN || DC Fan ||
0x80A5 || ENUM_OUT_STATE_BACKUP_OPER || NASA_OUTDOOR_BACKUP_OPERATION || Backup operation operation status On/Off ||
0x80A6 || ENUM_OUT_STATE_COMP_PROTECT_OPER || NASA_OUTDOOR_COM_PROTECT_OPERATIOIN || Compressor protection control operation status On/Off || 0 Off, 1 On
0x80A7 || ENUM_OUT_?? || NASA_OUTDOOR_DRED_LEVEL || || seen in NASA data from EHS Mono HT Quiet
0x80A8 || ENUM_OUT_?? || || ||
0x80A9 || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x80AA || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x80AB || ENUM_OUT_?? || || ||
0x80AC || ENUM_OUT_?? || NASA_OUTDOOR_ACCUM_RETURN2_VALVE || ||
0x80AE || ENUM_OUT_?? || || ||
0x80AF || ENUM_OUT_LOAD_BASEHEATER || NASA_OUTDOOR_BASE_HEATER || Base heater On/Off state for EHS || 0 Off, 1 On
0x80B1 || ENUM_OUT_?? || || ||
0x80B2 || ENUM_OUT_?? || NASA_OUTDOOR_CH_SWITCH_VALUE || || seen in NASA data from EHS Mono HT Quiet
0x80B4 || ENUM_OUT_STATE_ACCUM_VALVE_ONOFF || || ||
0x80B6 || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x80B8 || ENUM_OUT_LOAD_OIL_BYPASS1 || || ||
0x80B9 || ENUM_OUT_LOAD_OIL_BYPASS2 || || ||
0x80BC || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x80BE || ENUM_OUT_OP_A2_CURRENTMODE || || ||
0x80C1 || ENUM_OUT_LOAD_A2A_VALVE || || ||
0x80CE || ENUM_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x80D7 || ENUM_OUT_LOAD_PHEHEATER || || ||
0x80D8 || ENUM_OUT_EHS_WATEROUT_TYPE || || || 0 Default, 1 70°C
0x8200 || VAR_OUT_?? || NASA_OUTDOOR_OPMODE_OPTION || ||
0x8201 || VAR_OUT_?? || || ||
0x8202 || VAR_OUT_INSTALL_COMP_NUM || || Number of outdoor unit compressors ||
0x8204 || VAR_OUT_SENSOR_AIROUT || NASA_OUTDOOR_OUT_TEMP || Outdoor temperature ||
0x8206 || VAR_OUT_SENSOR_HIGHPRESS || NASA_OUTDOOR_HIGH_PRESS || High pressure ||
0x8208 || VAR_OUT_SENSOR_LOWPRESS || NASA_OUTDOOR_LOW_PRESS || low pressure ||
0x820A || VAR_OUT_SENSOR_DISCHARGE1 || NASA_OUTDOOR_DISCHARGE_TEMP1 || Discharge1 || The discharge temperature in a heat pump refers to the temperature of the refrigerant as it exits the compressor and enters the condenser.
0x820C || VAR_OUT_SENSOR_DISCHARGE2 || NASA_OUTDOOR_DISCHARGE_TEMP2 || Discharge2 ||
0x820E || VAR_OUT_SENSOR_DISCHARGE3 || NASA_OUTDOOR_DISCHARGE_TEMP3 || Discharge3 ||
0x8210 || || NASA_OUTDOOR_SUMPTEMP || ||
0x8217 || VAR_OUT_SENSOR_CT1 || NASA_OUTDOOR_CT1 || Compressor 1 current || very unprecise, just 1 fractional digit
0x8218 || VAR_OUT_SENSOR_CONDOUT || NASA_OUTDOOR_COND_OUT1 || Main heat exchanger outlet temperature ||
0x821A || VAR_OUT_SENSOR_SUCTION || NASA_OUTDOOR_SUCTION1_TEMP || Suction temperature ||
0x821C || VAR_OUT_SENSOR_DOUBLETUBE || NASA_OUTDOOR_DOUBLE_TUBE || Liquid pipe temperature ||
0x821E || VAR_OUTCD__SENSOR_EVIIN || NASA_OUTDOOR_EVI_IN || EVI IN ||
0x8220 || VAR_OUT_SENSOR_EVIOUT || NASA_OUTDOOR_EVI_OUT || EVI OUT ||
0x8222 || VAR_OUT_?? || NASA_OUTDOOR_OLP_TEMP || ||
0x8223 || VAR_OUT_CONTROL_TARGET_DISCHARGE || NASA_OUTDOOR_TARGET_DISCHARGE || Target discharge temperature ||
0x8224 || VAR_OUT_?? || || Temperature || seen in NASA data from EHS Mono HT Quiet
0x8225 || VAR_OUT_?? || || Temperature || seen in NASA data from EHS Mono HT Quiet
0x8226 || VAR_OUT_LOAD_FANSTEP1 || NASA_OUTDOOR_FAN_STEP1 || Outdoor Fan Step || Min 0, Max 10000
0x8227 || VAR_OUT_?? || NASA_OUTDOOR_FAN_STEP2 || ||
0x8228 || || NASA_OUTDOOR_LOADINGTIME || ||
0x8229 || VAR_OUT_LOAD_OUTEEV1 || NASA_OUTDOOR_MAINEEV1 || Main EEV1 || An Electronic Expansion Valve, or EEV for short, is installed before the evaporator in an air handler/coil and after the condenser in a heat pump. It regulates the refrigerant flow rate to control superheat at the evaporator outlet by opening and closing.
0x822A || VAR_OUT_LOAD_OUTEEV2 || NASA_OUTDOOR_MAINEEV2 || Main EEV2 ||
0x822B || VAR_OUT_LOAD_OUTEEV3 || NASA_OUTDOOR_MAINEEV3 || Main EEV3 ||
0x822C || VAR_OUT_LOAD_OUTEEV4 || NASA_OUTDOOR_MAINEEV4 || Main EEV4 ||
0x822D || VAR_OUT_LOAD_OUTEEV5 || NASA_OUTDOOR_MAINEEV5 || Main EEV5 ||
0x822E || VAR_OUT_LOAD_EVIEEV || NASA_OUTDOOR_EVIEEV || EVI EEV ||
0x822F || || NASA_OUTDOOR_HREEV || ||
0x8230 || VAR_OUT_?? || NASA_OUTDOOR_RUNNING_SUM_CAPA || ||
0x8231 || VAR_OUT_?? || NASA_OUTDOOR_HEATING_PERCENT || || seen in NASA data from EHS Mono HT Quiet
0x8233 || VAR_OUT_?? || NASA_OUTDOOR_OPERATION_CAPA_SUM || || division by 8.6 (better 8.5 ?). Does NOT show nominal Power Capacity, instead shows current ACTIVE Power Capacity
0x8234 || VAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x8235 || VAR_OUT_ERROR_CODE || || HTU error code ||
0x8236 || VAR_OUT_CONTROL_ORDER_CFREQ_COMP1 || NASA_OUTDOOR_COMP1_ORDER_HZ || Instruction frequency 1 ||
0x8237 || VAR_OUT_CONTROL_TARGET_CFREQ_COMP1 || NASA_OUTDOOR_COMP1_TARGET_HZ || Target frequency 1 ||
0x8238 || VAR_OUT_CONTROL_CFREQ_COMP1 || NASA_OUTDOOR_COMP1_RUN_HZ || Current frequency 1 ||
0x8239 || VAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x823B || VAR_OUT_SENSOR_DCLINK_VOLTAGE || NASA_OUTDOOR_DCLINK1_VOLT || DC Link1 (Inverter DC voltage input) || Min 0, Max 1000
0x823C || || || || seen in NASA data from EHS Mono HT Quiet
0x823D || VAR_OUT_LOAD_FANRPM1 || NASA_OUTDOOR_FAN_RPM1 || Outdoor Fan1 RPM ||
0x823E || VAR_OUT_LOAD_FANRPM2 || NASA_OUTDOOR_FAN_RPM2 || Outdoor Fan2 RPM ||
0x823F || VAR_OUT_?? || NASA_OUTDOOR_CONTROL_PRIME_UNIT || ||
0x8240 || || NASA_OUTDOOR_ODU_CAPA1 || current electric capacity of outdoor unit || value in percent, appears about every 140 seconds, not a reliable number
0x8241 || || NASA_OUTDOOR_ODU_CAPA2 || ||
0x8243 || VAR_OUT_?? || || ||
0x8244 || || NASA_OUTDOOR_OIL_RECOVERY_STEP || ||
0x8245 || || NASA_OUTDOOR_OIL_BALANCE_STEP || ||
0x8247 || VAR_OUT_?? || NASA_OUTDOOR_DEFROST_STEP || ||
0x8248 || VAR_OUT_?? || NASA_OUTDOOR_SAFETY_START || ||
0x8249 || VAR_OUT_?? || || ||
0x824B || VAR_OUT_?? || || ||
0x824C || VAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x824F || VAR_OUT_CONTROL_REFRIGERANTS_VOLUME || || Refrigerant amount ||
0x8254 || VAR_OUT_SENSOR_IPM1 || NASA_OUTDOOR_IPM_TEMP1 || IPM1 Temperature || Min -41, Max 150. The IPM is a component within the inverter system. It is responsible for converting the incoming direct current (DC) power from the power supply into alternating current (AC) power that drives the compressor motor. The term "intelligent" is often used because the IPM includes sophisticated electronics and control algorithms that optimize the motor's performance.
0x8255 || VAR_OUT_SENSOR_IPM2 || NASA_OUTDOOR_IPM_TEMP2 || IPM2 Temperature ||
0x825A || VAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x825B || VAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x825C || VAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x825D || VAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x825E || VAR_OUT_SENSOR_TEMP_WATER || NASA_OUTDOOR_WATER_TEMP || Water Temperature ||
0x825F || VAR_OUT_SENSOR_PIPEIN1 || || ||
0x8260 || VAR_OUT_SENSOR_PIPEIN2 || || ||
0x8261 || VAR_OUT_SENSOR_PIPEIN3 || || ||
0x8262 || VAR_OUT_SENSOR_PIPEIN4 || || ||
0x8263 || VAR_OUT_SENSOR_PIPEIN5 || || ||
0x8264 || VAR_OUT_SENSOR_PIPEOUT1 || || ||
0x8265 || VAR_OUT_SENSOR_PIPEOUT2 || || ||
0x8266 || VAR_OUT_SENSOR_PIPEOUT3 || || ||
0x8267 || VAR_OUT_SENSOR_PIPEOUT4 || || ||
0x8268 || VAR_OUT_SENSOR_PIPEOUT5 || || ||
0x826B || VAR_OUT_MCU_SENSOR_SUBCOOLER_IN || || ||
0x826C || VAR_OUT_MCU_SENSOR_SUBCOOLER_OUT || || ||
0x826D || VAR_OUT_MCU_SUBCOOLER_EEV || || ||
0x826E || VAR_OUT_MCU_CHANGE_OVER_EEV1 || || ||
0x826F || VAR_OUT_MCU_CHANGE_OVER_EEV2 || || ||
0x8270 || VAR_OUT_MCU_CHANGE_OVER_EEV3 || || ||
0x8271 || VAR_OUT_MCU_CHANGE_OVER_EEV4 || || ||
0x8272 || VAR_OUT_MCU_CHANGE_OVER_EEV5 || || ||
0x8273 || VAR_OUT_MCU_CHANGE_OVER_EEV6 || || ||
0x8274 || VAR_OUT_CONTROL_ORDER_CFREQ_COMP2 || NASA_OUTDOOR_COMP2_ORDER_HZ || Instruction frequency 2 ||
0x8275 || VAR_OUT_CONTROL_TARGET_CFREQ_COMP2 || NASA_OUTDOOR_COMP2_TARGET_HZ || Target frequency 2 ||
0x8276 || VAR_OUT_CONTROL_CFREQ_COMP2 || NASA_OUTDOOR_COMP2_RUN_HZ || Current frequency 2 ||
0x8277 || VAR_OUT_SENSOR_CT2 || NASA_OUTDOOR_CT2 || Compressor 2 current ||
0x8278 || VAR_OUT_SENSOR_OCT1 || NASA_OUTDOOR_OCT1 || Compressor OCT1 ||
0x8279 || || NASA_OUTDOOR_OCT2 || ||
0x827A || VAR_OUT_CONTROL_DSH1 || || Just for EHS HTU ||
0x827E || || NASA_OUTDOOR_ODU_CAPA3 || ||
0x827F || || NASA_OUTDOOR_ODU_CAPA4 || ||
0x8280 || VAR_OUT_SENSOR_TOP1 || NASA_OUTDOOR_TOP_SENSOR_TEMP1 || Top1 ||
0x8281 || VAR_OUT_SENSOR_TOP2 || NASA_OUTDOOR_TOP_SENSOR_TEMP2 || Top2 ||
0x8282 || || NASA_OUTDOOR_TOP_SENSOR_TEMP3 || ||
0x8287 || VAR_OUT_INSTALL_CAPA || NASA_OUTDOOR_HP || Outdoor unit horsepower || unknown UNIT "HP"
0x8298 || || NASA_OUTDOOR_COOL_SUM_CAPA || ||
0x829A || VAR_OUT_SENSOR_SUCTION2_1SEC || NASA_OUTDOOR_SUCTION2_TEMP || ||
0x829B || || NASA_OUTDOOR_CT_RESTRICT_OPTION || ||
0x829C || || NASA_OUTDOOR_COMPENSATE_COOL_CAPA || ||
0x829D || || NASA_OUTDOOR_COMPENSATE_HEAT_CAPA || ||
0x829F || VAR_OUT_SENSOR_SAT_TEMP_HIGH_PRESSURE || NASA_OUTDOOR_HIGH_PRESS_TEMP || High pressure saturation temperature ||
0x82A0 || VAR_OUT_SENSOR_SAT_TEMP_LOW_PRESSURE || NASA_OUTDOOR_LOW_PRESS_TEMP || Low pressure saturation temperature ||
0x82A2 || VAR_OUT_?? || || ||
0x82A3 || || NASA_OUTDOOR_CT3 || ||
0x82A4 || || NASA_OUTDOOR_OCT3 || ||
0x82A6 || || NASA_OUTDOOR_FAN_IPM1_TEMP || ||
0x82A7 || || NASA_OUTDOOR_FAN_IPM2_TEMP || ||
0x82A8 || VAR_OUT_CONTROL_IDU_TOTAL_ABSCAPA || || ||
0x82A9 || undefined || || || same value as 0x82A8
0x82AF || VAR_OUT_INSTALL_COND_SIZE || || ||
0x82B2 || VAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x82B3 || || NASA_OUTDOOR_DCLINK2_VOLT || ||
0x82B5 || VAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x82B6 || VAR_OUT_?? || || ||
0x82B8 || VAR_OUT_SENSOR_MIDPRESS || NASA_OUTDOOR_MID_PRESS || medium pressure ||
0x82B9 || || NASA_OUTDOOR_FAN_CT1 || ||
0x82BA || || NASA_OUTDOOR_FAN_CT2 || ||
0x82BC || VAR_OUT_PROJECT_CODE || NASA_OUTDOOR_PROJECT_CODE || Project code ||
0x82BD || VAR_OUT_LOAD_FLUX_VARIABLE_VALVE || NASA_OUTDOOR_FLUX_VARIABLE_VALVE || Flow Control ||
0x82BE || VAR_OUT_SENSOR_CONTROL_BOX || NASA_OUTDOOR_CBOX_TEMP || Contor Box Temp ||
0x82BF || VAR_OUT_SENSOR_CONDOUT2 || NASA_OUTDOOR_COND_OUT2 || Sub heat exchanger outlet temperature ||
0x82C0 || || NASA_OUTDOOR_COMP3_ORDER_HZ || ||
0x82C1 || || NASA_OUTDOOR_COMP3_TARGET_HZ || ||
0x82C2 || || NASA_OUTDOOR_COMP3_RUN_HZ || ||
0x82C3 || || NASA_OUTDOOR_DCLINK3_VOLT || ||
0x82C4 || || NASA_OUTDOOR_IPM_TEMP3 || ||
0x82C8 || VAR_OUT_SENSOR_ACCUM_TEMP || NASA_OUTDOOR_ACCUM_TEMP || Accumulator outlet temperature ||
0x82C9 || VAR_OUT_SENSOR_ENGINE_WATER_TEMP || NASA_OUTDOOR_ENGINE_WATER_TEMP || Engine water temperature ||
0x82CA || VAR_OUT_OIL_BYPASS_VALVE || NASA_OUTDOOR_OIL_BYPASS_VALVE || Oil Bypass Valve ||
0x82CB || VAR_OUT_SUCTION_OVER_HEAT || NASA_OUTDOOR_SUCTION_OVER_HEAT || Suction superheat ||
0x82CC || VAR_OUT_SUB_COND_OVER_HEAT || NASA_OUTDOOR_SUB_COND_OVER_HEAT || Sub heat exchanger outlet superheat ||
0x82CD || VAR_OUT_OVER_COOL || NASA_OUTDOOR_OVER_COOL || Outdoor unit supercooling ||
0x82CE || VAR_OUT_COND_OVER_COOL || NASA_OUTDOOR_COND_OVER_COOL || Outdoor heat exchanger subcooling degree ||
0x82CF || VAR_OUT_ENGINE_RPM || NASA_OUTDOOR_ENGINE_RPM || Engine RPM ||
0x82D0 || VAR_OUT_APPEARANCE_RPM || NASA_OUTDOOR_APPEARANCE_RPM || Appearance RPM ||
0x82D1 || VAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x82D2 || VAR_OUT_SUB_COND_EEV_STEP || NASA_OUTDOOR_SUB_COND_EEV_STEP || Sub EEV ||
0x82D3 || || NASA_OUTDOOR_SNOW_LEVEL || ||
0x82D4 || VAR_OUT_?? || || ||
0x82D5 || || NASA_OUTDOOR_UPL_TP_COOL || ||
0x82D6 || || NASA_OUTDOOR_UPL_TP_HEAT || ||
0x82D9 || VAR_OUT_?? || || ||
0x82DA || VAR_OUT_?? || || ||
0x82DB || VAR_OUT_PHASE_CURRENT || NASA_OUTDOOR_PHASE_CURRENT || Phase current value ||
0x82DC || VAR_OUT_?? || || ||
0x82DD || VAR_OUT_?? || || ||
0x82DE || VAR_OUT_SENSOR_EVAIN || NASA_OUTDOOR_EVA_IN || Eva In for EHS ||
0x82DF || VAR_OUT_SENSOR_TW1 || NASA_OUTDOOR_TW1_TEMP || Water In 1 for EHS ||
0x82E0 || VAR_OUT_SENSOR_TW2 || NASA_OUTDOOR_TW2_TEMP || Water In 2 for EHS ||
0x82E1 || VAR_OUT_?? || || ||
0x82E3 || VAR_OUT_PRODUCT_OPTION_CAPA || || Outdoor unit product option capacity (based on 0.1Kw) for EHS ||
0x82E7 || VAR_OUT_SENSOR_TOTAL_SUCTION || || Total Suction Sensor || Min -41, Max 150
0x82E8 || VAR_OUT_LOAD_MCU_HR_BYPASS_EEV || || MCU HR Bypass EEV opening diagram ||
0x82E9 || VAR_OUT_SENSOR_PFCM1 || || PFCM#1 element temperature || Min -54, Max 3000
0x82ED || VAR_OUT_?? || || ||
0x82F5 || VAR_OUT_HIGH_OVERLOAD_DETECT || || PFCM#1 element temperature ||
0x82F6 || VAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x82F9 || VAR_OUT_SENSOR_SUCTION3_1SEC || || Suction3 temperature ||
0x82FC || VAR_OUT_LOAD_EVI_SOL_EEV || || EVI SOL EEV ||
0x82FD || VAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x8401 || LVAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x8404 || LVAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x8405 || LVAR_OUT_LOAD_COMP1_RUNNING_TIME || NASA_OUTDOOR_COMP1_RUNNING_TIME || OutdoorTableCompressorRunningTime 1 || hours
0x8406 || LVAR_OUT_?? || NASA_OUTDOOR_COMP2_RUNNING_TIME || OutdoorTableCompressorRunningTime 2 ||
0x8408 || LVAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x8409 || LVAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x840B || LVAR_OUT_AUTO_INSPECT_RESULT0 || || ||
0x840C || LVAR_OUT_AUTO_INSPECT_RESULT1 || || ||
0x840E || || NASA_OUTDOOR_COMP3_RUNNING_TIME || ||
0x8411 || LVAR_OUT_?? || NASA_OUTDOOR_CONTROL_WATTMETER_1UNIT || Instantaneous power consumption of outdoor unit. One outdoor unit. Not used by the controller. || appears about every 135 seconds, so less often than 0x8413
0x8412 || || NASA_OUTDOOR_CONTROL_WATTMETER_1UNIT_ACCUM || Cumulative power consumption of outdoor unit. One outdoor unit. Not used by the controller. || never seen in NASA data from EHS Mono HT Quiet
0x8413 || LVAR_OUT_CONTROL_WATTMETER_1W_1MIN_SUM || NASA_OUTDOOR_CONTROL_WATTMETER_ALL_UNIT || Outdoor unit instantaneous power consumption. Sum of modules || appears about every 30 seconds, not once in a minute
0x8414 || LVAR_OUT_?? || NASA_OUTDOOR_CONTROL_WATTMETER_ALL_UNIT_ACCUM || Outdoor unit cumulative power consumption. Sum of modules || value is Wh, so do div 1000
0x8415 || LVAR_OUT_?? || NASA_OUTDOOR_CONTROL_WATTMETER_TOTAL_SUM || Total (indoor + outdoor) instantaneous power consumption || never seen in NASA data from EHS Mono HT Quiet
0x8416 || LVAR_OUT_?? || NASA_OUTDOOR_CONTROL_WATTMETER_TOTAL_SUM_ACCUM || Total (indoor + outdoor) cumulative power consumption || never seen in NASA data from EHS Mono HT Quiet
0x8417 || LVAR_OUT_?? || NASA_OUTDOOR_VARIABLE_SETUP_INFO || ||
0x841A || LVAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x841F || LVAR_OUT_?? || || || seen in NASA data from EHS Mono HT Quiet
0x8601 || STR_OUT_INSTALL_INVERTER_AND_BOOTLOADER_INFO || NASA_OUTDOOR_SUBMICOM || Structure Type ||
0x8608 || STR_OUT_?? || || Structure Type || seen in NASA data from EHS Mono HT Quiet
0x860A || STR_OUT_BASE_OPTION || || Structure Type ||
0x860C || STR_OUT_?? || || Structure Type ||
0x860D || STR_OUT_INSTALL_MODEL_INFO || NASA_OUTDOOR_MODELINFORMATION || Structure Type ||
0x860F || STR_OUT_INSTALL_OUTDOOR_SETUP_INFO || NASA_OUTDOOR_SETUP_INFO || Structure Type ||
0x8613 || STR_OUT_REF_CHECK_INFO || || Structure Type ||

View File

@@ -0,0 +1,761 @@
0x0000 || || || ||
0x0004 || || || ||
0x0007 || || || ||
0x0008 || || || ||
0x000A || || || ||
0x000D || || || ||
0x000E || || || ||
0x000F || || || ||
0x0010 || || || ||
0x0011 || || || ||
0x0012 || || || ||
0x0013 || || || ||
0x0014 || || || ||
0x0015 || || || ||
0x0016 || || || ||
0x0017 || || || ||
0x0018 || || || ||
0x0019 || || || ||
0x001A || || || ||
0x001B || || || ||
0x001C || || || ||
0x001D || || || ||
0x001E || || || ||
0x001F || || || ||
0x0020 || || || ||
0x0021 || || || ||
0x0023 || || || ||
0x0025 || ENUM || || ||
0x0202 || VAR || false || ||
0x0203 || || || ||
0x0204 || || || ||
0x0205 || || || ||
0x0206 || || || ||
0x0207 || VAR || false || ||
0x0208 || || || ||
0x0209 || || || ||
0x0210 || || || ||
0x0211 || VAR || false || ||
0x0213 || || || ||
0x0214 || || || ||
0x0217 || || || ||
0x0401 || LVAR || false || ||
0x0402 || LVAR || false || ||
0x0403 || || || ||
0x0406 || || || ||
0x0407 || || || ||
0x0408 || LVAR || false || ||
0x0409 || LVAR || false || ||
0x040A || LVAR || false || ||
0x040B || LVAR || false || || LogicalAnd 0xFF
0x040C || LVAR || false || ||
0x040D || LVAR || false || ||
0x040E || LVAR || false || ||
0x040F || LVAR || false || ||
0x0410 || LVAR || false || ||
0x0411 || LVAR || false || Celsius || (value & 0xFFFF0000u) >> 16) / 10.0;
0x0412 || LVAR || false || Celsius || (value & 0xFFFF0000u) >> 16) / 10.0;
0x0413 || LVAR || false || Celsius || (value & 0xFFFF0000u) >> 16) / 10.0;
0x0414 || LVAR || false || Celsius || (value & 0xFFFF0000u) >> 16) / 10.0;
0x0415 || LVAR || false || ||
0x0416 || LVAR || false || ||
0x0417 || LVAR || || ||
0x0418 || LVAR || || ||
0x0419 || LVAR || || ||
0x041B || LVAR || || ||
0x041C || || || ||
0x041D || || || ||
0x041E || || || ||
0x041F || || || ||
0x0420 || || || ||
0x0421 || || || ||
0x0422 || || || ||
0x0423 || || || ||
0x0434 || || || ||
0x0435 || || || ||
0x0436 || || || ||
0x0437 || || || ||
0x0438 || || || ||
0x0439 || || || ||
0x043A || || || ||
0x043B || || || ||
0x043C || || || ||
0x043D || || || ||
0x043E || || || ||
0x043F || || || ||
0x0440 || || || ||
0x0441 || || || ||
0x0442 || || || ||
0x0443 || || || ||
0x0444 || || || ||
0x0445 || || || ||
0x0448 || LVAR || false || ||
0x0600 || STR || || ||
0x0601 || STR || || ||
0x0602 || STR || || ||
0x0603 || STR || || ||
0x0604 || || || ||
0x0605 || STR || || ||
0x0607 || STR || || || null terminated string, first byte is = first Char
0x0608 || STR || || ||
0x060C || STR || || ||
0x0613 || || || ||
0x0619 || || || ||
0x061A || STR || || || null terminated string, first byte is = byte( length of string)
0x061C || STR || || ||
0x061F || STR || || ||
0x2000 || || || ||
0x2001 || || || ||
0x2002 || || || ||
0x2003 || || || ||
0x2004 || ENUM || || ||
0x2006 || || || ||
0x2007 || || || ||
0x2008 || || || ||
0x2009 || || || ||
0x200A || || || ||
0x200F || ENUM || || ||
0x2010 || ENUM || || ||
0x2012 || ENUM || || ||
0x2017 || || || ||
0x2018 || || || ||
0x22F7 || VAR || || ||
0x22F9 || VAR || || ||
0x22FA || VAR || || ||
0x22FB || VAR || || ||
0x22FC || VAR || || ||
0x22FD || VAR || || ||
0x22FE || VAR || || ||
0x22FF || VAR || || ||
0x2400 || LVAR || || ||
0x2401 || LVAR || || ||
0x24FB || LVAR || || ||
0x24FC || LVAR || || ||
0x4000 || ENUM || || ||
0x4001 || ENUM || || ||
0x4002 || ENUM || || ||
0x4003 || ENUM || || ||
0x4004 || ENUM || || ||
0x4006 || ENUM || || ||
0x4007 || ENUM || || ||
0x4008 || ENUM || || ||
0x400F || ENUM || || ||
0x4010 || ENUM || || ||
0x4011 || ENUM || || ||
0x4012 || ENUM || || ||
0x4015 || ENUM || || ||
0x4018 || ENUM || || ||
0x4019 || ENUM || || ||
0x401B || ENUM || || ||
0x4023 || ENUM || || ||
0x4024 || ENUM || || ||
0x4025 || || || ||
0x4027 || ENUM || || ||
0x4028 || ENUM || || ||
0x4029 || ENUM || || ||
0x402A || ENUM || || ||
0x402B || ENUM || || ||
0x402D || ENUM || || ||
0x402E || ENUM || || ||
0x402F || ENUM || || ||
0x4031 || ENUM || || ||
0x4035 || ENUM || || ||
0x4038 || ENUM || || ||
0x403D || || || ||
0x403E || || || ||
0x403F || || || ||
0x4040 || || || ||
0x4041 || || || ||
0x4042 || || || ||
0x4043 || ENUM || || ||
0x4045 || || || ||
0x4046 || ENUM || || ||
0x4047 || ENUM || || ||
0x4048 || ENUM || || ||
0x404F || ENUM || || ||
0x4050 || || || ||
0x4051 || ENUM || || ||
0x4059 || ENUM || || ||
0x405B || || || ||
0x405C || || || ||
0x405D || || || ||
0x405E || || || ||
0x405F || ENUM || || ||
0x4060 || ENUM || || ||
0x4063 || || || ||
0x4064 || || || ||
0x4065 || ENUM || || ||
0x4066 || ENUM || || ||
0x4067 || ENUM || || ||
0x4068 || ENUM || || ||
0x4069 || ENUM || || ||
0x406A || ENUM || || ||
0x406B || ENUM || || ||
0x406C || ENUM || || ||
0x406D || ENUM || || ||
0x406E || ENUM || || ||
0x406F || ENUM || || ||
0x4070 || ENUM || || ||
0x4073 || ENUM || || ||
0x4074 || ENUM || || ||
0x4076 || ENUM || || || 0 means no temp sensor, 1 means temp sensor present.
0x4077 || ENUM || || ||
0x407B || ENUM || || ||
0x407D || ENUM || || ||
0x407E || ENUM || || ||
0x4085 || ENUM || || ||
0x4086 || ENUM || || ||
0x4087 || ENUM || || ||
0x4089 || ENUM || || ||
0x408A || ENUM || || ||
0x4093 || ENUM || || ||
0x4094 || ENUM || || ||
0x4095 || ENUM || || ||
0x4096 || ENUM || || ||
0x4097 || ENUM || || ||
0x4098 || ENUM || || ||
0x4099 || ENUM || || ||
0x409A || ENUM || || ||
0x409B || ENUM || || ||
0x409C || ENUM || || ||
0x409D || ENUM || || ||
0x409E || ENUM || || ||
0x409F || ENUM || || ||
0x40A0 || ENUM || || ||
0x40A1 || ENUM || || ||
0x40A2 || ENUM || || ||
0x40A3 || ENUM || || ||
0x40A4 || ENUM || || ||
0x40A5 || ENUM || || ||
0x40A6 || ENUM || || ||
0x40A7 || ENUM || || ||
0x40B1 || || || ||
0x40B4 || ENUM || || ||
0x40B5 || ENUM || || ||
0x40BB || ENUM || || ||
0x40BC || ENUM || || ||
0x40BD || ENUM || || ||
0x40C0 || ENUM || || ||
0x40C1 || ENUM || || ||
0x40C2 || ENUM || || ||
0x40C3 || ENUM || || ||
0x40C4 || ENUM || || [%] ||
0x40C5 || ENUM || || ||
0x40C6 || ENUM || || ||
0x40C7 || || || ||
0x40C8 || || || ||
0x40C9 || || || ||
0x40CA || || || ||
0x40CB || || || ||
0x40CC || || || ||
0x40CD || || || ||
0x40CE || || || ||
0x40CF || || || ||
0x40D0 || || || ||
0x40D1 || || || ||
0x40D2 || || || ||
0x40D5 || ENUM || || ||
0x40D6 || ENUM || || ||
0x40E3 || ENUM || || ||
0x40E7 || ENUM || || ||
0x40F7 || ENUM || || ||
0x40FB || ENUM || || ||
0x40FC || ENUM || || ||
0x4101 || ENUM || || ||
0x4102 || ENUM || || ||
0x4103 || ENUM || || ||
0x4104 || ENUM || || ||
0x4105 || ENUM || || ||
0x4107 || ENUM || || ||
0x4108 || ENUM || || ||
0x410D || ENUM || || ||
0x4113 || ENUM || || ||
0x4117 || ENUM || || ||
0x4118 || ENUM || || || 0 means no temp sensor, 1 means temp sensor present.
0x4119 || ENUM || || ||
0x411A || ENUM || || ||
0x411B || ENUM || || ||
0x411C || ENUM || || ||
0x411D || ENUM || || ||
0x411E || ENUM || || ||
0x4123 || ENUM || || ||
0x4124 || ENUM || || ||
0x4125 || ENUM || || ||
0x4127 || ENUM || || ||
0x4128 || ENUM || || ||
0x412A || ENUM || || ||
0x412D || ENUM || || ||
0x4147 || ENUM || || ||
0x4149 || ENUM || || ||
0x4201 || VAR || true || Celsius || division by 10
0x4202 || VAR || true || Celsius || division by 10
0x4203 || VAR || true || Celsius || division by 10
0x4204 || VAR || true || Celsius || division by 10
0x4205 || VAR || true || Celsius || division by 10
0x4206 || VAR || true || Celsius || division by 10
0x4207 || VAR || true || Celsius || subtract 55
0x4208 || || || ||
0x4209 || || || ||
0x420B || VAR || true || Celsius || division by 10
0x420C || VAR || true || Celsius || division by 10
0x4211 || VAR || false || kW || division by 8.6
0x4212 || VAR || false || kW || division by 8.6
0x4213 || VAR || || ||
0x4217 || VAR || false || ||
0x4218 || VAR || false || ||
0x4219 || || || ||
0x421A || || || ||
0x421B || VAR || false || ||
0x4220 || || || ||
0x4229 || VAR || || ||
0x422A || VAR || true || Celsius || division by 10
0x422B || VAR || true || Celsius || division by 10
0x4235 || VAR || true || Celsius || division by 10
0x4236 || VAR || true || Celsius || division by 10
0x4237 || VAR || true || Celsius || division by 10
0x4238 || VAR || true || Celsius || division by 10
0x4239 || VAR || true || Celsius || division by 10
0x423E || VAR || || ||
0x4247 || VAR || true || Celsius || division by 10
0x4248 || VAR || true || Celsius || division by 10
0x424A || VAR || true || Celsius || division by 10
0x424B || VAR || true || Celsius || division by 10
0x424C || VAR || true || Celsius || division by 10
0x424D || VAR || true || Celsius || division by 10
0x424E || VAR || true || Celsius || division by 10
0x424F || VAR || true || Celsius || division by 10
0x4250 || VAR || true || Celsius || division by 10
0x4251 || VAR || true || Celsius || division by 10
0x4252 || VAR || true || Celsius || division by 10
0x4253 || VAR || true || Celsius || division by 10
0x4254 || VAR || true || Celsius || division by 10
0x4255 || VAR || true || Celsius || division by 10
0x4256 || VAR || true || Celsius || division by 10
0x4257 || VAR || true || Celsius || division by 10
0x4258 || VAR || true || Celsius || division by 10
0x4259 || VAR || true || Celsius || division by 10
0x425A || VAR || true || Celsius || division by 10
0x425B || VAR || true || Celsius || division by 10
0x425C || VAR || true || Celsius || division by 10
0x425D || VAR || true || Celsius || division by 10
0x425E || VAR || true || Celsius || division by 10
0x425F || VAR || true || Celsius || division by 10
0x4260 || VAR || true || Celsius || division by 10
0x4261 || VAR || true || Celsius || division by 10
0x4262 || VAR || true || Celsius || division by 10
0x4263 || VAR || false || ||
0x4264 || VAR || false || ||
0x4265 || VAR || false || ||
0x4266 || VAR || false || ||
0x4267 || VAR || true || Celsius || division by 10
0x4268 || VAR || true || Celsius || division by 10
0x4269 || VAR || false || ||
0x426A || VAR || true || Celsius || division by 10
0x426B || VAR || true || ||
0x426C || VAR || true || || division by 0.1
0x426D || VAR || true || Celsius || division by 10
0x426E || VAR || true || Celsius || division by 10
0x426F || VAR || true || Celsius || division by 10
0x4270 || VAR || true || Celsius || division by 10
0x4271 || VAR || true || Celsius || division by 10
0x4272 || VAR || true || Celsius || division by 10
0x4273 || VAR || true || Celsius || division by 10
0x4274 || VAR || true || Celsius || division by 10
0x4275 || VAR || true || Celsius || division by 10
0x4276 || VAR || true || Celsius || division by 10
0x4277 || VAR || true || Celsius || division by 10
0x4278 || VAR || true || Celsius || division by 10
0x4279 || VAR || true || Celsius || division by 10
0x427A || VAR || true || Celsius || division by 10
0x427B || VAR || true || Celsius || division by 10
0x427C || VAR || true || Celsius || division by 10
0x427D || VAR || false || ||
0x427E || VAR || false || ||
0x427F || VAR || true || Celsius || division by 10
0x4284 || || || ||
0x4286 || VAR || false || Celsius || division by 10
0x4287 || VAR || false || Celsius || division by 10
0x4288 || VAR || false || ||
0x4289 || VAR || false || || division by 0.1
0x428A || VAR || false || Celsius || division by 10
0x428C || VAR || true || Celsius || division by 10
0x428D || VAR || || ||
0x4290 || || || ||
0x4291 || || || ||
0x4292 || || || ||
0x4293 || || || ||
0x4294 || || || ||
0x4295 || || || ||
0x4296 || || || ||
0x4297 || VAR || true || ||
0x4298 || VAR || true || ||
0x4299 || || || ||
0x429A || || || ||
0x429B || || || ||
0x429C || || || ||
0x429F || VAR || false || ||
0x42A1 || VAR || false || ||
0x42A3 || VAR || false || ||
0x42A5 || VAR || true || Celsius || division by 10
0x42A6 || VAR || true || Celsius || division by 10
0x42A7 || VAR || true || Celsius || division by 10
0x42A8 || VAR || true || Celsius || division by 10
0x42A9 || VAR || true || Celsius || division by 10
0x42AA || VAR || true || Celsius || division by 10
0x42AB || VAR || true || Celsius || division by 10
0x42AC || VAR || true || Celsius || division by 10
0x42AD || VAR || true || Celsius || division by 10
0x42AE || VAR || true || Celsius || division by 10
0x42AF || VAR || true || Celsius || division by 10
0x42B0 || VAR || true || Celsius || division by 10
0x42B1 || VAR || false || ||
0x42B2 || VAR || false || ||
0x42B3 || VAR || false || ||
0x42C2 || VAR || true || Celsius || division by 10
0x42C3 || VAR || true || Celsius || division by 10
0x42C4 || VAR || true || kgfcm2 || division by 100
0x42C5 || VAR || true || kgfcm2 || division by 100
0x42C9 || VAR || true || Celsius || division by 10
0x42CA || VAR || false || ||
0x42CB || VAR || false || ||
0x42CC || VAR || false || ||
0x42CD || VAR || true || Celsius || division by 10
0x42CE || VAR || false || || division by 60 (not documented in NASA.ptc)
0x42CF || VAR || false || Enthalpy || division by 10
0x42D0 || VAR || false || ||
0x42D1 || VAR || false || ||
0x42D2 || VAR || false || ||
0x42D3 || VAR || false || ||
0x42D4 || VAR || true || Celsius || division by 10
0x42D6 || VAR || true || Celsius || division by 10
0x42D7 || VAR || true || Celsius || division by 10
0x42D8 || VAR || true || Celsius || division by 10
0x42D9 || VAR || true || Celsius || division by 10
0x42DB || VAR || false || Celsius || division by 10
0x42DC || VAR || false || Celsius || division by 10
0x42DD || VAR || false || Celsius || division by 10
0x42DE || VAR || false || Celsius || division by 10
0x42E8 || VAR || false || || division by 10
0x42E9 || VAR || true || || division by 10
0x42ED || VAR || true || ||
0x42EE || VAR || true || ||
0x42EF || VAR || true || ||
0x42F0 || VAR || true || Celsius || division by 10
0x42F1 || VAR || || ||
0x4301 || VAR || || ||
0x4302 || VAR || false || kW || division by 8.6
0x4401 || LVAR || || ||
0x4405 || || || ||
0x4406 || || || ||
0x4407 || || || ||
0x440A || LVAR || false || || LogicalAnd 0x00000002 + division by 2
0x440E || LVAR || || ||
0x440F || LVAR || || ||
0x4415 || LVAR || false || ||
0x4418 || LVAR || false || ||
0x441B || LVAR || false || ||
0x441F || LVAR || false || ||
0x4420 || LVAR || false || ||
0x4423 || LVAR || || ||
0x4424 || LVAR || || ||
0x4426 || LVAR || false || kW || division by 1000
0x4427 || LVAR || false || kW || division by 1000
0x4604 || STR || || ||
0x4608 || STR || || ||
0x4612 || STR || || ||
0x4619 || STR || || ||
0x461A || STR || || ||
0x461C || STR || || ||
0x461D || STR || || ||
0x461E || STR || || ||
0x8000 || ENUM || || ||
0x8001 || ENUM || || ||
0x8002 || ENUM || || ||
0x8003 || ENUM || || ||
0x8005 || ENUM || || ||
0x800D || ENUM || || ||
0x8010 || ENUM || || ||
0x8011 || ENUM || || ||
0x8012 || ENUM || || ||
0x8013 || ENUM || || ||
0x8014 || ENUM || || ||
0x8015 || || || ||
0x8016 || || || ||
0x8017 || ENUM || || ||
0x8018 || ENUM || || ||
0x8019 || ENUM || || ||
0x801A || ENUM || || ||
0x801F || ENUM || || ||
0x8020 || ENUM || || ||
0x8021 || ENUM || || ||
0x8022 || ENUM || || ||
0x8023 || ENUM || || ||
0x8024 || || || ||
0x8025 || ENUM || || ||
0x8026 || ENUM || || ||
0x8027 || ENUM || || ||
0x802A || ENUM || || ||
0x8031 || ENUM || || ||
0x8032 || ENUM || || ||
0x8033 || ENUM || || ||
0x8034 || ENUM || || ||
0x8037 || ENUM || || ||
0x803B || ENUM || || ||
0x803C || ENUM || || ||
0x803F || ENUM || || ||
0x8043 || ENUM || || ||
0x8045 || ENUM || || ||
0x8046 || ENUM || || ||
0x8047 || ENUM || || ||
0x8048 || ENUM || || ||
0x8049 || ENUM || || ||
0x804A || ENUM || || ||
0x804B || ENUM || || ||
0x804C || ENUM || || ||
0x804D || ENUM || || ||
0x804E || ENUM || || ||
0x804F || ENUM || || ||
0x8050 || ENUM || || ||
0x8051 || ENUM || || ||
0x8052 || ENUM || || ||
0x8053 || ENUM || || ||
0x8054 || ENUM || || ||
0x8055 || ENUM || || ||
0x8058 || ENUM || || ||
0x8059 || ENUM || || ||
0x805A || ENUM || || ||
0x805B || ENUM || || ||
0x805C || ENUM || || ||
0x805D || ENUM || || ||
0x805E || ENUM || || ||
0x8061 || ENUM || || ||
0x8062 || || || ||
0x8063 || ENUM || || ||
0x8065 || ENUM || || ||
0x8066 || ENUM || || ||
0x8077 || ENUM || || ||
0x8078 || ENUM || || ||
0x8079 || ENUM || || ||
0x807A || ENUM || || ||
0x807B || ENUM || || ||
0x807C || ENUM || || ||
0x807D || ENUM || || ||
0x807E || ENUM || || ||
0x807F || ENUM || || ||
0x8081 || ENUM || || ||
0x8083 || ENUM || || ||
0x808C || ENUM || || ||
0x808D || ENUM || || ||
0x808E || ENUM || false || || LogicalAnd 0x0F
0x808F || ENUM || || ||
0x8092 || ENUM || false || ||
0x8099 || ENUM || false || ||
0x809C || ENUM || || ||
0x809D || ENUM || || ||
0x809E || ENUM || || ||
0x80A5 || ENUM || || ||
0x80A6 || ENUM || || ||
0x80A7 || ENUM || || ||
0x80A8 || ENUM || || ||
0x80A9 || ENUM || || ||
0x80AA || ENUM || || ||
0x80AB || ENUM || || ||
0x80AC || || || ||
0x80AE || ENUM || || ||
0x80AF || ENUM || || ||
0x80B1 || ENUM || || ||
0x80B2 || ENUM || || ||
0x80B4 || ENUM || || ||
0x80B6 || ENUM || || ||
0x80B8 || ENUM || || ||
0x80B9 || ENUM || || ||
0x80BC || ENUM || || ||
0x80BE || ENUM || || ||
0x80C1 || ENUM || || ||
0x80CE || ENUM || || ||
0x80D7 || ENUM || || ||
0x80D8 || ENUM || || ||
0x8200 || VAR || || ||
0x8201 || VAR || || ||
0x8202 || VAR || false || ||
0x8204 || VAR || true || Celsius || division by 10
0x8206 || VAR || true || kgfcm2 || division by 10
0x8208 || VAR || true || kgfcm2 || division by 10
0x820A || VAR || true || Celsius || division by 10
0x820C || VAR || true || Celsius || division by 10
0x820E || VAR || true || Celsius || division by 10
0x8210 || || || ||
0x8217 || VAR || false || || division by 10
0x8218 || VAR || true || Celsius || division by 10
0x821A || VAR || true || Celsius || division by 10
0x821C || VAR || true || Celsius || division by 10
0x821E || VAR || true || Celsius || division by 10
0x8220 || VAR || true || Celsius || division by 10
0x8222 || VAR || || ||
0x8223 || VAR || true || Celsius || division by 10
0x8224 || VAR || true || Celsius || division by 10
0x8225 || VAR || true || Celsius || division by 10
0x8226 || VAR || false || ||
0x8227 || VAR || || ||
0x8228 || || || ||
0x8229 || VAR || false || ||
0x822A || VAR || false || ||
0x822B || VAR || false || ||
0x822C || VAR || false || ||
0x822D || VAR || false || ||
0x822E || VAR || false || ||
0x822F || || || ||
0x8230 || VAR || || ||
0x8231 || VAR || || ||
0x8233 || VAR || || || division by 8.6 (better 8.5 ?)
0x8234 || VAR || || ||
0x8235 || VAR || false || ||
0x8236 || VAR || false || ||
0x8237 || VAR || false || ||
0x8238 || VAR || false || ||
0x8239 || VAR || || ||
0x823B || VAR || false || ||
0x823C || VAR || false || ||
0x823D || VAR || false || ||
0x823E || VAR || false || ||
0x823F || VAR || false || || appears when using S-NET pro 2 software
0x8240 || || || ||
0x8241 || || || ||
0x8243 || VAR || || ||
0x8244 || || || ||
0x8245 || || || ||
0x8247 || VAR || || ||
0x8248 || VAR || || ||
0x8249 || VAR || || ||
0x824B || VAR || || ||
0x824C || VAR || || ||
0x824F || VAR || false || || division by 10
0x8254 || VAR || true || Celsius || division by 10
0x8255 || VAR || true || Celsius || division by 10
0x825A || VAR || true || Celsius || division by 10
0x825B || VAR || true || Celsius || division by 10
0x825C || VAR || true || Celsius || division by 10
0x825D || VAR || true || Celsius || division by 10
0x825E || VAR || true || Celsius || division by 10
0x825F || VAR || true || Celsius || division by 10
0x8260 || VAR || true || Celsius || division by 10
0x8261 || VAR || true || Celsius || division by 10
0x8262 || VAR || true || Celsius || division by 10
0x8263 || VAR || true || Celsius || division by 10
0x8264 || VAR || true || Celsius || division by 10
0x8265 || VAR || true || Celsius || division by 10
0x8266 || VAR || true || Celsius || division by 10
0x8267 || VAR || true || Celsius || division by 10
0x8268 || VAR || true || Celsius || division by 10
0x826B || VAR || true || Celsius || division by 10
0x826C || VAR || true || Celsius || division by 10
0x826D || VAR || false || ||
0x826E || VAR || false || ||
0x826F || VAR || false || ||
0x8270 || VAR || false || ||
0x8271 || VAR || false || ||
0x8272 || VAR || false || ||
0x8273 || VAR || false || ||
0x8274 || VAR || false || ||
0x8275 || VAR || false || ||
0x8276 || VAR || false || ||
0x8277 || VAR || false || ||
0x8278 || VAR || false || ||
0x8279 || || || ||
0x827A || VAR || true || Celsius || division by 10
0x827E || || || ||
0x827F || || || ||
0x8280 || VAR || true || Celsius || division by 10
0x8281 || VAR || true || Celsius || division by 10
0x8282 || || || ||
0x8287 || VAR || false || HP ||
0x8298 || || || ||
0x829A || VAR || true || Celsius || division by 10
0x829B || || || ||
0x829C || || || ||
0x829D || || || ||
0x829F || VAR || true || Celsius || division by 10
0x82A0 || VAR || true || Celsius || division by 10
0x82A2 || VAR || || ||
0x82A3 || || || ||
0x82A4 || || || ||
0x82A6 || || || ||
0x82A7 || || || ||
0x82A8 || VAR || true || || division by 8.6 = kW
0x82A9 || VAR || true || ||
0x82AF || VAR || false || ||
0x82B2 || VAR || || ||
0x82B3 || || || ||
0x82B5 || VAR || || ||
0x82B6 || VAR || || ||
0x82B8 || VAR || true || kgfcm2 || division by 10
0x82B9 || || || ||
0x82BA || || || ||
0x82BC || VAR || true || ||
0x82BD || VAR || true || ||
0x82BE || VAR || true || Celsius || division by 10
0x82BF || VAR || true || Celsius || division by 10
0x82C0 || || || ||
0x82C1 || || || ||
0x82C2 || || || ||
0x82C3 || || || ||
0x82C4 || || || ||
0x82C8 || VAR || true || Celsius || division by 10
0x82C9 || VAR || true || Celsius || division by 10
0x82CA || VAR || false || ||
0x82CB || VAR || false || || division by 10
0x82CC || VAR || false || || division by 10
0x82CD || VAR || false || ||
0x82CE || VAR || false || || division by 10
0x82CF || VAR || false || ||
0x82D0 || VAR || false || RPM || division by 10
0x82D1 || VAR || || ||
0x82D2 || VAR || false || ||
0x82D3 || || || ||
0x82D4 || VAR || || ||
0x82D5 || || || ||
0x82D6 || || || ||
0x82D9 || VAR || || ||
0x82DA || VAR || || ||
0x82DB || VAR || false || ||
0x82DC || VAR || || ||
0x82DD || VAR || || ||
0x82DE || VAR || true || Celsius || division by 10
0x82DF || VAR || true || Celsius || division by 10
0x82E0 || VAR || true || Celsius || division by 10
0x82E1 || VAR || || ||
0x82E3 || VAR || false || kW || division by 10.0
0x82E7 || VAR || true || Celsius || division by 10.0
0x82E8 || VAR || false || ||
0x82E9 || VAR || true || Celsius || division by 10
0x82ED || VAR || || ||
0x82F5 || VAR || false || ||
0x82F6 || VAR || || ||
0x82F9 || VAR || true || Celsius || division by 10
0x82FC || VAR || true || || -32767 up to 32767
0x82FD || VAR || || ||
0x8401 || LVAR || || ||
0x8404 || LVAR || || ||
0x8405 || LVAR || false || ||
0x8406 || LVAR || false || ||
0x8408 || LVAR || || ||
0x8409 || LVAR || || ||
0x840B || LVAR || false || ||
0x840C || LVAR || false || ||
0x840E || || || ||
0x8411 || LVAR || || ||
0x8412 || || || ||
0x8413 || LVAR || false || kW || division by 1000
0x8414 || LVAR || false || kW || division by 1000
0x8415 || LVAR || || ||
0x8416 || LVAR || || ||
0x8417 || LVAR || || ||
0x841A || LVAR || || ||
0x841F || LVAR || || ||
0x8601 || STR || || ||
0x8608 || STR || || ||
0x860A || STR || || ||
0x860C || STR || || ||
0x860D || STR || || ||
0x860F || STR || || ||
0x8613 || STR || || ||

6
requirements.txt Normal file
View File

@@ -0,0 +1,6 @@
aiofiles>=24.1.0
pyserial>=3.5
pyserial-asyncio>=0.6
PyYAML>=6.0.2
serial>=0.0.97
gmqtt>=0.7.0

258
startEHSSentinel.py Normal file
View File

@@ -0,0 +1,258 @@
import asyncio
import serial
import serial_asyncio
import traceback
from MessageProcessor import MessageProcessor
from EHSArguments import EHSArguments
from EHSConfig import EHSConfig
from EHSExceptions import MessageWarningException
from MQTTClient import MQTTClient
import aiofiles
import json
import struct
import binascii
# Get the logger
from CustomLogger import logger, setSilent
from NASAPacket import NASAPacket
version = "0.1SNAPSHOT"
async def main():
"""
Main function to start the EHS Sentinel application.
This function performs the following steps:
1. Logs the startup banner and version information.
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.
Args:
None
Returns:
None
"""
logger.info("####################################################################################################################")
logger.info("# #")
logger.info("# ###### ## ## ##### ##### ###### ## ## ######## ###### ## ## ###### ## #")
logger.info("# ## # ## ## ## ## ## ## ## # ### ## ## ## ## ## ### ## ## # ## #")
logger.info("# ## ## ## ## ## ## #### ## ## ## #### ## ## ## #")
logger.info("# #### ###### ##### ##### #### ####### ## ## ####### #### ## #")
logger.info("# ## ## ## ## ## ## ## #### ## ## ## #### ## ## #")
logger.info("# ## # ## ## ## ## ## ## ## # ## ### ## ## ## ### ## # ## #")
logger.info("# ###### ## ## ##### ##### ###### ## ## #### ###### ## ## ###### ####### #")
logger.info("# #")
logger.info("####################################################################################################################")
logger.info(f"Starting EHSSentinel {version} written by echoDave")
logger.info("")
logger.info("Reading Arguments ...")
args = EHSArguments()
logger.info("Reading Configuration ...")
config = EHSConfig()
logger.info("connecting to MQTT Borker ...")
mqtt = MQTTClient()
await mqtt.connect()
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}")
async with aiofiles.open(args.DUMPFILE, mode='r') as file:
async for line in file:
line = json.loads(line.strip())
await process_packet(line, args)
else:
# we are not in dryrun mode, so we need to read from Serial Pimort
await serial_read(config, args)
async def process_buffer(buffer, args):
"""
Processes a buffer of data asynchronously, identifying and handling packets based on specific criteria.
Args:
buffer (list): A list of bytes representing the buffer to be processed.
args (Any): Additional arguments to be passed to the packet processing function.
Notes:
- The function continuously checks the buffer for data.
- If the first byte of the buffer is 0x32, it is considered a start byte.
- The packet size is determined by combining the second and third bytes of the buffer.
- If the buffer contains enough data for a complete packet, the packet is processed.
- If the buffer does not contain enough data, the function waits and checks again.
- Non-start bytes are removed from the buffer.
- The function sleeps for 0.03 seconds between iterations to avoid busy-waiting.
Logging:
- Logs the buffer size when data is present.
- Logs when the start byte is recognized.
- Logs the calculated packet size.
- Logs the complete packet and the last byte read when a packet is processed.
- Logs if the buffer is too small to read a complete packet.
- Logs if a received byte is not a start byte.
"""
while True:
if buffer:
logger.debug(f"Buffersize: {len(buffer)}")
if buffer[0] == 0x32:
logger.debug("Start Byte recognized")
packet_size = ((buffer[1] << 8) | buffer[2]) +2
logger.debug(f"Readed packet size: {packet_size-1}")
if len(buffer) > packet_size-1:
packet = []
for i in range(0, len(buffer)):
packet.append(buffer[i])
if i == packet_size-1: #buffer[i] == 0x34 or
logger.debug(f"Complete Packet: {i}/{packet_size-1}")
logger.debug(f"Last Byte readed: {hex(buffer[i])}")
await process_packet(packet, args)
del buffer[0:i]
break
else:
logger.debug(f"Buffer to small to read hole packet, wait... buffer size {len(buffer)} packet size {packet_size}")
else:
logger.debug(f"Received byte not a startbyte 0x32 {buffer[0]} / {hex(buffer[0])}")
buffer.pop(0)
await asyncio.sleep(0.03)
async def serial_read(config, args):
"""
Asynchronously reads data from a serial connection and processes it.
Args:
config (object): Configuration object containing serial connection parameters.
args (object): Additional arguments for buffer processing.
This function establishes a serial connection using parameters from the config object,
reads data from the serial port until a specified delimiter (0x34) is encountered,
and appends the received data to a buffer. It also starts an asynchronous task to
process the buffer.
The serial connection is configured with the following parameters:
- Device URL: config.SERIAL['device']
- Baudrate: config.SERIAL['baudrate']
- Parity: Even
- Stopbits: One
- Bytesize: Eight
- RTS/CTS flow control: Enabled
- Timeout: 0
The function runs an infinite loop to continuously read data from the serial port.
"""
buffer = []
loop = asyncio.get_running_loop()
reader, writer = await serial_asyncio.open_serial_connection(
loop=loop,
url=config.SERIAL['device'],
baudrate=config.SERIAL['baudrate'],
parity=serial.PARITY_EVEN,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
rtscts=True,
timeout=0
)
# 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))
# Read loop
while True:
data = await reader.readuntil(b'\x34') # Read up to end of next message 0x34
if data:
buffer.extend(data)
logger.debug(f"Received: {[hex(x) for x in data]}")
async def serial_write(writer, reader):
"""
TODO Not used yet, only for future use...
Asynchronously writes data to the serial port.
This function sends data through the serial port at regular intervals.
Args:
transport: The serial transport object.
args: Additional arguments.
Returns:
None
"""
while True:
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']
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
async def process_packet(buffer, args):
"""
Asynchronously processes a packet buffer.
If `dumpWriter` is `None`, it attempts to process the packet using `MessageProcessor`.
If a `MessageWarningException` is raised, it logs a warning and skips the packet.
If any other exception is raised, it logs an error, skips the packet, and logs the stack trace.
If `dumpWriter` is not `None`, it writes the buffer to `dumpWriter`.
Args:
buffer (bytes): The packet buffer to be processed.
"""
if args.DUMPFILE and not args.DRYRUN:
async with aiofiles.open(args.DUMPFILE, "a") as dumpWriter:
await dumpWriter.write(f"{buffer}\n")
else:
try:
nasa_packet = NASAPacket()
nasa_packet.parse(buffer)
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)
except ValueError as e:
logger.warning("Value Error on parsing Packet, Packet will be skipped")
logger.warning(f"Error processing message: {e}")
except MessageWarningException as e:
logger.warning("Warnung accured, Packet will be skipped")
logger.warning(f"Error processing message: {e}")
except Exception as e:
logger.error("Error Accured, Packet will be skipped")
logger.error(f"Error processing message: {e}")
logger.error(traceback.format_exc())
if __name__ == "__main__":
asyncio.run(main())

21
todo.txt Normal file
View File

@@ -0,0 +1,21 @@
MQTT Publisher:
- nachrichten als einfache topic verschicken *erledigt*
- nachrichten als HASS Auto Discovery Topic verschicken *erledigt*
Config File:
- definierne und parametrisieren *erledigt*
- parameter validierung *erledigt*
- alle hard coded parms auf configfile auslagern *erledigt*
- NasaDataRepository hier als Parm abspeichern *erledigt*
- include / exclude measurments einbauen (wenn exclude definiert ist, werden alle inkludiert und exclude exkludiert
wenn include definiert ist, werden alle exkludiert und nur die aus include inkludiert)
MessageProcessor:
- ls singleton ausprobieren *erledigt*
- NasaDataRepository auf den ConfigValue abändern *erledigt*
- calculating generated output (NASA_OUTDOOR_TW2_TEMP - NASA_OUTDOOR_TW1_TEMP) * (VAR_IN_FLOW_SENSOR_CALC/60) * 4190 *erledigt*
Allgemein:
- requierments.txt aufbauen *erledigt*
- als venv zum laufen bekommen
- hZ units erwietern für bekannte typen