Compare commits

...

2 commits

Author SHA1 Message Date
db97b8eb69 Reconnect when WiFi lacks a valid IP address 2023-07-07 22:29:34 -04:00
b5b9b492f2 Handle MQTT connection failures 2023-07-07 22:28:30 -04:00

270
main.py
View file

@ -20,6 +20,7 @@ VOLUME_MAX = const(128)
MQTT_KEEPALIVE = const(60)
MQTT_UPDATE_INTERVAL = const(60)
MQTT_RECONNECT_INTERVAL = const(60)
channels = ["LINE 1", "LINE 2", "LINE 3", "PHONO"]
state = StateTree(
@ -72,6 +73,124 @@ mqtt = None
mqtt_client_id = ubinascii.hexlify(machine.unique_id())
mqtt_broker = settings["mqtt"]["broker"]
mqtt_prefix = settings["mqtt"]["prefix"]
last_mqtt_attempt = 0
def mqtt_init():
print("Starting MQTT client")
mqtt = MQTTClient(mqtt_client_id, mqtt_broker, keepalive=MQTT_KEEPALIVE)
mqtt.set_callback(on_message)
mqtt.set_last_will(f"{mqtt_prefix}/status", b"offline", retain=True)
mqtt.connect()
mqtt.subscribe(f"{mqtt_prefix}/set")
mqtt_device = {
"identifiers": mqtt_client_id,
"manufacturer": "correl",
"model": "digital-audio-switch",
"name": "Digital Audio Switch",
}
mqtt.publish(
f"homeassistant/number/digital-audio-switch/volume-left/config".encode(),
json.dumps(
{
"name": "Digital Audio Switch Volume (Left)",
"command_topic": f"{mqtt_prefix}/set",
"command_template": '{"volume": {"left": {{value}}}}',
"state_topic": f"{mqtt_prefix}/state",
"value_template": "{{ value_json.volume.left }}",
"availability_topic": f"{mqtt_prefix}/status",
"min": 0,
"max": VOLUME_MAX,
"mode": "slider",
"step": 1,
"unique_id": "digital-audio-switch-volume-left",
"device": mqtt_device,
}
).encode(),
retain=True,
)
mqtt.publish(
f"homeassistant/number/digital-audio-switch/volume-right/config".encode(),
json.dumps(
{
"name": "Digital Audio Switch Volume (Right)",
"command_topic": f"{mqtt_prefix}/set",
"command_template": '{"volume": {"right": {{value}}}}',
"state_topic": f"{mqtt_prefix}/state",
"value_template": "{{ value_json.volume.right }}",
"availability_topic": f"{mqtt_prefix}/status",
"min": 0,
"max": VOLUME_MAX,
"mode": "slider",
"step": 1,
"unique_id": "digital-audio-switch-volume-right",
"device": mqtt_device,
}
).encode(),
retain=True,
)
mqtt.publish(
f"homeassistant/number/digital-audio-switch/volume-master/config".encode(),
json.dumps(
{
"name": "Digital Audio Switch Volume (Master)",
"command_topic": f"{mqtt_prefix}/set",
"command_template": '{"volume": {"right": {{value}}, "left": {{value}}}}',
"state_topic": f"{mqtt_prefix}/state",
"value_template": """
{%set values = value_json.volume.left,
value_json.volume.right %}
{{ values|max }}
""",
"availability_topic": f"{mqtt_prefix}/status",
"min": 0,
"max": VOLUME_MAX,
"mode": "slider",
"step": 1,
"unique_id": "digital-audio-switch-volume-master",
"device": mqtt_device,
}
).encode(),
retain=True,
)
mqtt.publish(
f"homeassistant/switch/digital-audio-switch/mute/config".encode(),
json.dumps(
{
"name": "Digital Audio Switch Mute",
"command_topic": f"{mqtt_prefix}/set",
"payload_on": '{"volume": {"muted": "ON"}}',
"payload_off": '{"volume": {"muted": "OFF"}}',
"state_on": "ON",
"state_off": "OFF",
"state_topic": f"{mqtt_prefix}/state",
"value_template": "{{ value_json.volume.muted }}",
"availability_topic": f"{mqtt_prefix}/status",
"unique_id": "digital-audio-switch-volume-mute",
"device": mqtt_device,
}
).encode(),
retain=True,
)
mqtt.publish(
f"homeassistant/select/digital-audio-switch/channel/config".encode(),
json.dumps(
{
"name": "Digital Audio Switch Channel",
"command_topic": f"{mqtt_prefix}/set",
"command_template": '{"channel": "{{value}}"}',
"state_topic": f"{mqtt_prefix}/state",
"value_template": "{{ value_json.channel }}",
"availability_topic": f"{mqtt_prefix}/status",
"options": channels,
"unique_id": "digital-audio-switch-channel",
"device": mqtt_device,
}
).encode(),
retain=True,
)
return mqtt
def on_message(topic, msg):
@ -95,7 +214,8 @@ def on_message(topic, msg):
def loop():
global mqtt, state, last_update, rotary, rotary_button, rotary_value
global mqtt, state, last_update, last_mqtt_attempt
global rotary, rotary_button, rotary_value
rotary_button.update()
if rotary_button.was_clicked():
@ -133,134 +253,32 @@ def loop():
if sta_if.active() and not sta_if.isconnected():
state["network"] = "ACT"
if sta_if.isconnected():
if state["network"] != "OK":
ip, _, _, _ = sta_if.ifconfig()
ip, _, _, _ = sta_if.ifconfig()
if ip == "0.0.0.0":
# Something went wrong, try to reconnect
print("IP invalid, retrying WiFi connection")
state["network"] = "ACT"
sta_if.active(True)
sta_if.connect(settings["wifi"]["ssid"], settings["wifi"]["password"])
elif state["network"] != "OK":
print(f"WIFI Connected to {sta_if.config('ssid')}")
print(f"IP Address: {ip}")
state["network"] = "OK"
if not mqtt:
print("Starting MQTT client")
mqtt = MQTTClient(mqtt_client_id, mqtt_broker, keepalive=MQTT_KEEPALIVE)
mqtt.set_callback(on_message)
mqtt.set_last_will(f"{mqtt_prefix}/status", b"offline", retain=True)
mqtt.connect()
mqtt.subscribe(f"{mqtt_prefix}/set")
mqtt_device = {
"identifiers": mqtt_client_id,
"manufacturer": "correl",
"model": "digital-audio-switch",
"name": "Digital Audio Switch",
}
mqtt.publish(
f"homeassistant/number/digital-audio-switch/volume-left/config".encode(),
json.dumps(
{
"name": "Digital Audio Switch Volume (Left)",
"command_topic": f"{mqtt_prefix}/set",
"command_template": '{"volume": {"left": {{value}}}}',
"state_topic": f"{mqtt_prefix}/state",
"value_template": "{{ value_json.volume.left }}",
"availability_topic": f"{mqtt_prefix}/status",
"min": 0,
"max": VOLUME_MAX,
"mode": "slider",
"step": 1,
"unique_id": "digital-audio-switch-volume-left",
"device": mqtt_device,
}
).encode(),
retain=True,
)
mqtt.publish(
f"homeassistant/number/digital-audio-switch/volume-right/config".encode(),
json.dumps(
{
"name": "Digital Audio Switch Volume (Right)",
"command_topic": f"{mqtt_prefix}/set",
"command_template": '{"volume": {"right": {{value}}}}',
"state_topic": f"{mqtt_prefix}/state",
"value_template": "{{ value_json.volume.right }}",
"availability_topic": f"{mqtt_prefix}/status",
"min": 0,
"max": VOLUME_MAX,
"mode": "slider",
"step": 1,
"unique_id": "digital-audio-switch-volume-right",
"device": mqtt_device,
}
).encode(),
retain=True,
)
mqtt.publish(
f"homeassistant/number/digital-audio-switch/volume-master/config".encode(),
json.dumps(
{
"name": "Digital Audio Switch Volume (Master)",
"command_topic": f"{mqtt_prefix}/set",
"command_template": '{"volume": {"right": {{value}}, "left": {{value}}}}',
"state_topic": f"{mqtt_prefix}/state",
"value_template": """
{%set values = value_json.volume.left,
value_json.volume.right %}
{{ values|max }}
""",
"availability_topic": f"{mqtt_prefix}/status",
"min": 0,
"max": VOLUME_MAX,
"mode": "slider",
"step": 1,
"unique_id": "digital-audio-switch-volume-master",
"device": mqtt_device,
}
).encode(),
retain=True,
)
mqtt.publish(
f"homeassistant/switch/digital-audio-switch/mute/config".encode(),
json.dumps(
{
"name": "Digital Audio Switch Mute",
"command_topic": f"{mqtt_prefix}/set",
"payload_on": '{"volume": {"muted": "ON"}}',
"payload_off": '{"volume": {"muted": "OFF"}}',
"state_on": "ON",
"state_off": "OFF",
"state_topic": f"{mqtt_prefix}/state",
"value_template": "{{ value_json.volume.muted }}",
"availability_topic": f"{mqtt_prefix}/status",
"unique_id": "digital-audio-switch-volume-mute",
"device": mqtt_device,
}
).encode(),
retain=True,
)
mqtt.publish(
f"homeassistant/select/digital-audio-switch/channel/config".encode(),
json.dumps(
{
"name": "Digital Audio Switch Channel",
"command_topic": f"{mqtt_prefix}/set",
"command_template": '{"channel": "{{value}}"}',
"state_topic": f"{mqtt_prefix}/state",
"value_template": "{{ value_json.channel }}",
"availability_topic": f"{mqtt_prefix}/status",
"options": channels,
"unique_id": "digital-audio-switch-channel",
"device": mqtt_device,
}
).encode(),
retain=True,
)
if state.changed or utime.time() - last_update >= MQTT_UPDATE_INTERVAL:
topic = f"{mqtt_prefix}/state".encode()
payload = json.dumps(state.dictionary).encode()
print(f"MQTT -> [{topic}] {payload}")
mqtt.publish(f"{mqtt_prefix}/status", b"online", retain=True)
mqtt.publish(topic, payload, retain=True)
last_update = utime.time()
mqtt.check_msg()
if not mqtt and utime.time() - last_mqtt_attempt >= MQTT_RECONNECT_INTERVAL:
last_mqtt_attempt = utime.time()
try:
mqtt = mqtt_init()
except OSError as e:
print(f"Failed to connect to MQTT ({mqtt_broker}): {e}")
if mqtt:
if state.changed or utime.time() - last_update >= MQTT_UPDATE_INTERVAL:
topic = f"{mqtt_prefix}/state".encode()
payload = json.dumps(state.dictionary).encode()
print(f"MQTT -> [{topic}] {payload}")
mqtt.publish(f"{mqtt_prefix}/status", b"online", retain=True)
mqtt.publish(topic, payload, retain=True)
last_update = utime.time()
mqtt.check_msg()
if oled and state.changed:
oled.fill(0)
oled.framebuf.rect(10, 0, 92, 8, 1)