I think I got it to work. It took a long debate with ChatGPT, but here are the final cleaned up instructions:
Dinotec to Home Assistant via WebSocket and AppDaemon (Full Guide)
1. Install the AppDaemon Add-on
- In Home Assistant:
- Go to Settings > Add-ons > Add-on Store
- Search for AppDaemon and install it
- In the AppDaemon settings:
- Enable Start on boot
- Enable Show in sidebar (optional)
- Start the AppDaemon add-on
- Open the Log tab and confirm you see:
INFO AppDaemon: You are now ready to run Apps!
2. Locate the apps Folder
The AppDaemon apps folder is located at:
/config/appdaemon/apps
Tip: If it does not exist, see this helpful thread.
3. Install python-socketio (Client Library)
You must add the dependency in AppDaemon’s config to make WebSocket connections.
- Go to Settings > Add-ons > AppDaemon > Configuration
- Update it to include:
system_packages: []
python_packages:
- "python-socketio[client]"
init_commands: []
- Click Save
- Go to the Info tab and Restart AppDaemon
This installs python-socketio into the AppDaemon container.
4. Create the Dinotec WebSocket Script
- In
/config/appdaemon/apps/, create a file: dinotec.py
- Paste the following:
import appdaemon.plugins.hass.hassapi as hass
import socketio
import logging
class DinotecClient(hass.Hass):
def initialize(self):
# Enable debug logging for troubleshooting
logging.getLogger('socketio').setLevel(logging.DEBUG)
logging.getLogger('engineio').setLevel(logging.DEBUG)
self.log("Starting Dinotec WebSocket Client")
self.sio = socketio.Client()
# Handle successful connection
@self.sio.event
def connect():
self.log("Connected to Dinotec")
client_id = "onhEPSHfqJ7kWswy" # Replace if dynamic
self.sio.emit("subscribe-dinoaccess", client_id)
self.log(f"Sent subscribe-dinoaccess event with client_id: {client_id}")
# Handle disconnection
@self.sio.event
def disconnect():
self.log("Disconnected from Dinotec")
# Handle the incoming data and create sensors
@self.sio.on("dinoaccess-status")
def handle_dinoaccess(data):
self.log(f"Received dinoaccess-status: {data}")
# Mapping from data keys to human-readable sensor names
sensor_map = {
"7": ("Pool Temperature", 0.1, "°C"),
"66": ("Pool Redox", None, "mV"),
"67": ("Pool pH", 0.01, None),
"85": ("Pool pH Probe Voltage", None, "mV"),
"86": ("Pool pH Probe Slope", None, None),
"87": ("Pool pH Probe Zero Point", None, "mV"),
}
for key, value in data.items():
if str(key) in sensor_map:
friendly_name, multiplier, unit = sensor_map[key]
entity_id = "sensor." + friendly_name.replace(" ", "_").lower()
self.log(entity_id)
attributes = {"friendly_name": friendly_name}
if unit is not None:
attributes["unit_of_measurement"] = unit
if multiplier is not None:
value *= multiplier
self.set_state(entity_id, state=value, attributes=attributes)
# Attempt to connect to the WebSocket server
try:
self.sio.connect(
f'https://remote.dinotec.de:3006/socket.io/?auth_token={self.args["auth_token"]}&EIO=3',
transports=['websocket']
)
except Exception as e:
self.log(f"Connection failed: {e}")
5. Create or Update apps.yaml
- In the same folder (
/config/appdaemon/apps/), create a file (or update): apps.yaml
- Paste this, replacing the token:
dinotec:
module: dinotec
class: DinotecClient
auth_token: "your_valid_token_here"
The auth_token is a long JWT you copy from your browser dev tools when logged in to Dinotec.