Skip to content

Commit

Permalink
Merge pull request #8 from Minims/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
Minims authored Sep 26, 2023
2 parents f37938b + dcc8f97 commit a3e4505
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 13 deletions.
47 changes: 42 additions & 5 deletions myFox2Mqtt/business/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
ha_discovery_alarm_actions,
ha_discovery_cameras,
ha_discovery_devices,
ha_discovery_scenario_actions,
DEVICE_CAPABILITIES,
ALARM_STATUS,
)
Expand Down Expand Up @@ -68,6 +69,24 @@ def ha_sites_config(
retain=True,
)

# Scenarios
scenarios = api.get_scenarios(site_id=site_id)
for scenario in scenarios:
if scenario.get("typeLabel") == "onDemand":
LOGGER.info(f"Found Scenario onDemand {scenario.get('label')}: {scenario.get('scenarioId')}")
play_scenario = ha_discovery_scenario_actions(
site=my_site,
scenario=scenario,
mqtt_config=mqtt_config,
)
mqtt_publish(
mqtt_client=mqtt_client,
topic=play_scenario.get("topic"),
payload=play_scenario.get("config"),
retain=True,
)
mqtt_client.client.subscribe(play_scenario.get("config").get("command_topic"))


def ha_devices_config(
api: MyFoxApi,
Expand All @@ -84,8 +103,8 @@ def ha_devices_config(
state_devices = api.get_devices_state(site_id=site_id)
other_devices = api.get_devices_other(site_id=site_id)
camera_devices = api.get_devices_camera(site_id=site_id)
scenarios = api.get_scenarios(site_id=site_id)
shutter_devices = api.get_devices_shutter(site_id=site_id)
socket_devices = api.get_devices_socket(site_id=site_id)

for device in my_devices:
LOGGER.info(f"Configuring Device: {device.label}")
Expand Down Expand Up @@ -245,6 +264,24 @@ def ha_devices_config(
)
mqtt_client.client.subscribe(shutter.get("config").get("command_topic"))

# Sockets
for socket_device in socket_devices:
if socket_device.get("deviceId") == device.device_id:
LOGGER.info(f"Found Socket for {device.device_id}: {socket_device.get('label')}")
socket = ha_discovery_devices(
site_id=site_id,
device=device,
mqtt_config=mqtt_config,
sensor_name="socket",
)
mqtt_publish(
mqtt_client=mqtt_client,
topic=socket.get("topic"),
payload=socket.get("config"),
retain=True,
)
mqtt_client.client.subscribe(socket.get("config").get("command_topic"))

# Works with Websockets
if "Télécommande 4 boutons" in device.device_definition.get("device_definition_label"):
LOGGER.info(f"Found {device.device_definition.get('device_definition_label')}")
Expand Down Expand Up @@ -311,7 +348,7 @@ def update_sites_status(
mqtt_client=mqtt_client,
topic=f"{mqtt_config.get('topic_prefix', 'myFox2mqtt')}/{site_id}/history",
payload=payload,
retain=False,
retain=True,
)

except Exception as exp:
Expand All @@ -326,7 +363,7 @@ def update_sites_status(
mqtt_client=mqtt_client,
topic=f"{mqtt_config.get('topic_prefix', 'myFox2mqtt')}/{site_id}/state",
payload={"security_level": ALARM_STATUS.get(status.get("payload").get("statusLabel"), "disarmed")},
retain=False,
retain=True,
)
except Exception as exp:
LOGGER.warning(f"Error while refreshing site: {exp}")
Expand Down Expand Up @@ -385,7 +422,7 @@ def update_devices_status(
mqtt_client=mqtt_client,
topic=f"{mqtt_config.get('topic_prefix', 'myFox2mqtt')}/{site_id}/{device.device_id}/state",
payload=payload,
retain=False,
retain=True,
)

except Exception as exp:
Expand Down Expand Up @@ -424,7 +461,7 @@ def update_camera_snapshot(
mqtt_client=mqtt_client,
topic=topic,
payload=byte_arr,
retain=False,
retain=True,
is_json=False,
)

Expand Down
26 changes: 21 additions & 5 deletions myFox2Mqtt/business/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
LOGGER = logging.getLogger(__name__)


def mqtt_publish(mqtt_client, topic, payload, qos=0, retain=False, is_json=True):
def mqtt_publish(mqtt_client, topic, payload, qos=0, retain=True, is_json=True):
"""MQTT publish"""
if is_json:
payload = json.dumps(payload)
payload = json.dumps(payload, ensure_ascii=False).encode("utf8")
mqtt_client.client.publish(topic, payload, qos=qos, retain=retain)


Expand All @@ -32,7 +32,7 @@ def update_device(api, mqtt_client, mqtt_config, site_id, device_id):
mqtt_client=mqtt_client,
topic=f"{mqtt_config.get('topic_prefix', 'myFox2mqtt')}/{site_id}/{device.device_id}/state",
payload=payload,
retain=False,
retain=True,
)
except Exception as exp:
LOGGER.warning(f"Error while refreshing {device.label}: {exp}")
Expand All @@ -49,7 +49,7 @@ def update_site(api, mqtt_client, mqtt_config, site_id):
mqtt_client=mqtt_client,
topic=f"{mqtt_config.get('topic_prefix', 'myFox2mqtt')}/{site_id}/state",
payload={"security_level": ALARM_STATUS.get(status.get("payload").get("statusLabel"), "disarmed")},
retain=False,
retain=True,
)
except Exception as exp:
LOGGER.warning(f"Error while refreshing site {site_id}: {exp}")
Expand Down Expand Up @@ -93,6 +93,22 @@ def consume_mqtt_message(msg, mqtt_config: dict, api: MyFoxApi, mqtt_client: cli
LOGGER.info(f"{text_payload} Shutter on {site_id} / {device_id}")
api.shutter_action_device(site_id=site_id, device_id=device_id, action=text_payload)

# Manage Socket
elif text_payload in ["on_socket", "off_socket"]:
site_id = msg.topic.split("/")[1]
device_id = msg.topic.split("/")[2]
action = text_payload.split("_")[0]
LOGGER.info(f"{action} Socket on {site_id} / {device_id}")
api.socket_action_device(site_id=site_id, device_id=device_id, action=action)

# Manage Scenarios
elif text_payload in ["play_scenario", "enable_scenario", "disbale_scenario"]:
site_id = msg.topic.split("/")[1]
scenario_id = msg.topic.split("/")[2]
action = text_payload.split("_")[0]
LOGGER.info(f"{text_payload} Scenario on {site_id} / {scenario_id}")
api.scenario_action(site_id=site_id, scenario_id=scenario_id, action=action)

# Manage Siren
elif text_payload == "panic":
site_id = msg.topic.split("/")[1]
Expand Down Expand Up @@ -150,7 +166,7 @@ def consume_mqtt_message(msg, mqtt_config: dict, api: MyFoxApi, mqtt_client: cli
mqtt_client,
topic,
byte_array,
retain=False,
retain=True,
is_json=False,
)

Expand Down
2 changes: 1 addition & 1 deletion myFox2Mqtt/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ version: "3"
services:
myfox2mqtt:
build: .
image: myfox2mqtt:v2023.9.3
image: myfox2mqtt:v2023.10.0
volumes:
- ./config:/config
36 changes: 36 additions & 0 deletions myFox2Mqtt/homeassistant/ha_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@
"type": "cover",
"config": {"pl_open": "open", "pl_close": "close", "pl_stop": "my", "optimistic": "true"},
},
"socket": {
"type": "switch",
"config": {
"pl_on": "on_socket",
"pl_off": "off_socket",
},
},
"image_detection_enabled": {
"type": "switch",
"config": {
Expand Down Expand Up @@ -725,6 +732,35 @@ def ha_discovery_alarm_actions(site: Site, mqtt_config: dict):
return site_config


def ha_discovery_scenario_actions(site: Site, scenario: dict, mqtt_config: dict):
"""Auto Discover Scenarios Actions"""
site_config = {}

site_info = {
"identifiers": [site.siteId],
"manufacturer": "MyFox",
"model": "MyFox HC2",
"name": "MyFox HC2",
"sw_version": "MyFox2MQTT",
}

command_topic = (
f"{mqtt_config.get('topic_prefix', 'myFox2mqtt')}/{site.siteId}/{scenario.get('scenarioId')}/command"
)
site_config[
"topic"
] = f"{mqtt_config.get('ha_discover_prefix', 'homeassistant')}/button/{site.siteId}/{scenario.get('scenarioId')}/config"
site_config["config"] = {
"name": scenario.get("label"),
"unique_id": f"{site.siteId}_{scenario.get('label')}",
"command_topic": command_topic,
"device": site_info,
"payload_press": "play_scenario",
}

return site_config


def ha_discovery_devices(
site_id: str,
device: Device,
Expand Down
2 changes: 1 addition & 1 deletion myFox2Mqtt/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from myfox.api import MyFoxApi
from myfox.websocket import MyFoxWebsocket

VERSION = "2023.9.3"
VERSION = "2023.10.0"


def myfox_loop(config, mqtt_client, api):
Expand Down
77 changes: 76 additions & 1 deletion myFox2Mqtt/myfox/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,8 +394,39 @@ def get_scenarios(
??
"""
response = self.get(f"/v2/site/{site_id}/scenario/items")
response.raise_for_status()
try:
content = response.json()
except JSONDecodeError:
response.raise_for_status()
LOGGER.info(f"Scenarios: {response.json()}")
return content.get("payload").get("items")

def scenario_action(
self,
site_id: str,
scenario_id: str,
action: str,
) -> Dict:
"""Make an action on a Scenario
Args:
site_id (str): Site ID
scenario_id (str): Scenario ID
action (str): Action
Returns:
str: Task ID
"""
if action not in ["enable", "disable", "play"]:
raise ValueError(f"Unknown action {action}")

response = self.post(
f"/v2/site/{site_id}/scenario/{scenario_id}/{action}",
json={},
)

LOGGER.info(f"Scenario Action: {response.status_code} => {response.text}")
response.raise_for_status()
return response.json()

def get_devices_temperature(self, site_id: str):
Expand Down Expand Up @@ -598,3 +629,47 @@ def shutter_action_device(
LOGGER.info(f"Shutter Action: {response.status_code} => {response.text}")
response.raise_for_status()
return response.json()

def get_devices_socket(self, site_id: str):
"""Get Devices Socket from a Site ID
Args:
site_id (Optional[str], optional): Site ID. Defaults to None.
Returns:
List[Device]: List of Device object
"""
response = self.get(f"/v2/site/{site_id}/device/socket/items")
try:
content = response.json()
except JSONDecodeError:
response.raise_for_status()
LOGGER.info(f"Devices Socket: {response.json()}")
return content.get("payload").get("items")

def socket_action_device(
self,
site_id: str,
device_id: str,
action: str,
) -> Dict:
"""Make an action on a Socket
Args:
site_id (str): Site ID
device_id (str): Device ID
action (str): Action
Returns:
str: Task ID
"""
if action not in ["on", "off"]:
raise ValueError(f"Unknown action {action}")

response = self.post(
f"/v2/site/{site_id}/device/{device_id}/socket/{action}",
json={},
)
LOGGER.info(f"Socket Action: {response.status_code} => {response.text}")
response.raise_for_status()
return response.json()

0 comments on commit a3e4505

Please sign in to comment.