jokob-sk / NetAlertX

🖧🔍 WIFI / LAN intruder detector. Scans for devices connected to your network and alerts you if new and unknown devices are found.
GNU General Public License v3.0
3.15k stars 186 forks source link

MQTT: Add device_class timestamp to attributes for first/last connection #819

Closed NightMean closed 1 month ago

NightMean commented 1 month ago

Is there an existing issue for this?

Is your feature request related to a problem? Please describe

Currently, MQTT sends the data to HomeAssistant for first/last_connection as a string in format 2024-10-01 15:56:15+02:00. This shows in HA as a simple text instead of a date entity that HA supports.

Describe the solution you'd like

Modify the MQTT data to also send device_class as timestamp for first/last_connection with the correct time format as 2024-10-01T15:56:15+02:00

Describe alternatives you've considered

None

Anything else?

With the help of ChatGPT, I managed to create a concept that already does this but it has a bug where the data is being sent twice. First in incorrect format that is currently in prod and afterwards in the format with the device_class. Unfortunately after many tries, I'm not able to fix it myself nor with ChatGPT as he is also bit lost on this :/ (I'm sure that for someone else the issue it will be obvious..) Of course, there might be a better way to do this but as I don't have enough knowledge in Python, this is what I managed to create with ChatGPT.

Here is the changed code for mqtt.py ```python from datetime import datetime # Function to adjust datetime format (adds 'T' between date and time) def adjust_datetime_format(datetime_str): # Convert "YYYY-MM-DD HH:MM:SS±HH:MM" to "YYYY-MM-DDTHH:MM:SS±HH:MM" return datetime_str.replace(' ', 'T') #------------------------------------------------------------------------------- for device in devices: # Create devices in Home Assistant - send config messages deviceId = 'mac_' + device["dev_MAC"].replace(" ", "").replace(":", "_").lower() devDisplayName = re.sub('[^a-zA-Z0-9-_\\s]', '', device["dev_Name"]) # Adjust datetime format as soon as we fetch it from the device object first_connection_time = adjust_datetime_format(str(device["dev_FirstConnection"])) last_connection_time = adjust_datetime_format(str(device["dev_LastConnection"])) # Prepare the devJson payload (including first_connection and last_connection) devJson = { "last_ip": device["dev_LastIP"], "is_new": str(device["dev_NewDevice"]), "vendor": sanitize_string(device["dev_Vendor"]), "mac_address": str(device["dev_MAC"]), "first_connection": first_connection_time, "last_connection": last_connection_time } # First connection sensor with device_class: timestamp first_connection_sensor = create_sensor(mqtt_client, deviceId, devDisplayName, 'sensor', 'first_connection', 'calendar-start', device["dev_MAC"]) first_connection_sensor.message["device_class"] = "timestamp" # Set device_class for first_connection # Publish first_connection sensor config (but don't send the state separately) publish_mqtt(mqtt_client, first_connection_sensor.topic, first_connection_sensor.message) # Last connection sensor with device_class: timestamp last_connection_sensor = create_sensor(mqtt_client, deviceId, devDisplayName, 'sensor', 'last_connection', 'calendar-end', device["dev_MAC"]) last_connection_sensor.message["device_class"] = "timestamp" # Set device_class for last_connection # Publish last_connection sensor config (but don't send the state separately) publish_mqtt(mqtt_client, last_connection_sensor.topic, last_connection_sensor.message) # Publish all device data (including first_connection and last_connection) in one JSON object to the same state_topic publish_mqtt(mqtt_client, first_connection_sensor.state_topic, devJson) # Create and update is_present sensor sensorConfig = create_sensor(mqtt_client, deviceId, devDisplayName, 'binary_sensor', 'is_present', 'wifi', device["dev_MAC"]) publish_mqtt(mqtt_client, sensorConfig.state_topic, { "is_present": to_binary_sensor(str(device["dev_PresentLastScan"])) } ) # Handle device_tracker sensorConfig = create_sensor(mqtt_client, deviceId, devDisplayName, 'device_tracker', 'is_home', 'home', device["dev_MAC"]) # are only valid states state = 'away' if to_binary_sensor(str(device["dev_PresentLastScan"])) == "ON": state = 'home' publish_mqtt(mqtt_client, sensorConfig.state_topic, state) # Publish device_tracker attributes publish_mqtt(mqtt_client, sensorConfig.json_attr_topic, devJson) ```

With the device_class = timestamp, the entities first and last_connection will look like this.

image

Am I willing to test this? 🧪

Can I help implement this? 👩‍💻👨‍💻

jokob-sk commented 1 month ago

Thanks for the detailed description, this helps a lot!

This should be available in the next release. It would be great if you could test this. Can you please switch to the netalertx-dev docker image (backup everything at first), in about 15 minutes (or after the last action finishes) from now.

Make sure you refresh your browser cache - and click the 🔄 refresh button in the top right corner.

Thanks in advance, j

NightMean commented 1 month ago

Just tested this, works better than my implementation :) (Knew there would be a better way) Thank you!

image