power: Add Home Assistant switch support
* power: Add Home Assistant switch support Signed-off-by: Sébastien Jousse <s.jousse@gmail.com>
This commit is contained in:
parent
40d4daa96b
commit
c53b95aa93
|
@ -172,7 +172,7 @@ gcode:
|
||||||
|
|
||||||
## `[power]`
|
## `[power]`
|
||||||
Enables device power control. Currently GPIO (relays), TPLink Smartplug,
|
Enables device power control. Currently GPIO (relays), TPLink Smartplug,
|
||||||
and Tasmota (via http) devices are supported.
|
and Tasmota (via http) devices, HomeAssistant switch are supported.
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
# moonraker.conf
|
# moonraker.conf
|
||||||
|
@ -258,6 +258,13 @@ password:
|
||||||
# "ID" in the "advanced information" section.
|
# "ID" in the "advanced information" section.
|
||||||
# Provide a user and password with access to "device control"
|
# Provide a user and password with access to "device control"
|
||||||
# and at least the specific device you want to control
|
# and at least the specific device you want to control
|
||||||
|
address:
|
||||||
|
port:
|
||||||
|
device:
|
||||||
|
token:
|
||||||
|
# The above options are used for "homeassistant" devices. The
|
||||||
|
# address should be a valid ip or hostname for the homeassistant controller.
|
||||||
|
# "device" should be the ID of the switch to control.
|
||||||
|
|
||||||
```
|
```
|
||||||
Below are some potential examples:
|
Below are some potential examples:
|
||||||
|
@ -294,6 +301,13 @@ type: shelly
|
||||||
address: 192.168.1.125
|
address: 192.168.1.125
|
||||||
user: user2
|
user: user2
|
||||||
password: password2
|
password: password2
|
||||||
|
|
||||||
|
[power homeassistant_switch]
|
||||||
|
type: homeassistant
|
||||||
|
address: 192.168.1.126
|
||||||
|
port: 8123
|
||||||
|
device: switch.1234567890abcdefghij
|
||||||
|
token: home-assistant-very-long-token
|
||||||
```
|
```
|
||||||
|
|
||||||
It is possible to toggle device power from the Klippy host, this can be done
|
It is possible to toggle device power from the Klippy host, this can be done
|
||||||
|
|
|
@ -38,6 +38,8 @@ class PrinterPower:
|
||||||
dev = Shelly(cfg)
|
dev = Shelly(cfg)
|
||||||
elif dev_type == "homeseer":
|
elif dev_type == "homeseer":
|
||||||
dev = HomeSeer(cfg)
|
dev = HomeSeer(cfg)
|
||||||
|
elif dev_type == "homeassistant":
|
||||||
|
dev = HomeAssistant(cfg)
|
||||||
else:
|
else:
|
||||||
raise config.error(f"Unsupported Device Type: {dev_type}")
|
raise config.error(f"Unsupported Device Type: {dev_type}")
|
||||||
self.devices[dev.get_name()] = dev
|
self.devices[dev.get_name()] = dev
|
||||||
|
@ -620,6 +622,83 @@ class HomeSeer(PowerDevice):
|
||||||
raise self.server.error(msg) from None
|
raise self.server.error(msg) from None
|
||||||
self.state = state
|
self.state = state
|
||||||
|
|
||||||
|
class HomeAssistant(PowerDevice):
|
||||||
|
def __init__(self, config):
|
||||||
|
super().__init__(config)
|
||||||
|
self.server = config.get_server()
|
||||||
|
self.addr = config.get("address")
|
||||||
|
self.port = config.getint("port", 8123)
|
||||||
|
self.device = config.get("device")
|
||||||
|
self.token = config.get("token")
|
||||||
|
|
||||||
|
async def _send_homeassistant_command(self, command):
|
||||||
|
if command == "on":
|
||||||
|
out_cmd = f"api/services/switch/turn_on"
|
||||||
|
body = {"entity_id": self.device}
|
||||||
|
method = "POST"
|
||||||
|
elif command == "off":
|
||||||
|
out_cmd = f"api/services/switch/turn_off"
|
||||||
|
body = {"entity_id": self.device}
|
||||||
|
method = "POST"
|
||||||
|
elif command == "info":
|
||||||
|
out_cmd = f"api/states/{self.device}"
|
||||||
|
method = "GET"
|
||||||
|
else:
|
||||||
|
raise self.server.error(
|
||||||
|
f"Invalid homeassistant command: {command}")
|
||||||
|
url = f"http://{self.addr}:{self.port}/{out_cmd}"
|
||||||
|
headers = {
|
||||||
|
'Authorization': f'Bearer {self.token}',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
data = ""
|
||||||
|
http_client = AsyncHTTPClient()
|
||||||
|
try:
|
||||||
|
if (method == "POST"):
|
||||||
|
response = await http_client.fetch(
|
||||||
|
url, method="POST", body=json.dumps(body), headers=headers)
|
||||||
|
data = json_decode(response.body)
|
||||||
|
else:
|
||||||
|
response = await http_client.fetch(
|
||||||
|
url, method="GET", headers=headers)
|
||||||
|
data = json_decode(response.body)
|
||||||
|
except Exception:
|
||||||
|
msg = f"Error sending homeassistant command: {command}"
|
||||||
|
logging.exception(msg)
|
||||||
|
raise self.server.error(msg)
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def initialize(self):
|
||||||
|
await self.refresh_status()
|
||||||
|
|
||||||
|
def get_device_info(self):
|
||||||
|
return {
|
||||||
|
**super().get_device_info(),
|
||||||
|
'type': "homeassistant"
|
||||||
|
}
|
||||||
|
|
||||||
|
async def refresh_status(self):
|
||||||
|
try:
|
||||||
|
res = await self._send_homeassistant_command("info")
|
||||||
|
state = res[f"state"]
|
||||||
|
except Exception:
|
||||||
|
self.state = "error"
|
||||||
|
msg = f"Error Refeshing Device Status: {self.name}"
|
||||||
|
logging.exception(msg)
|
||||||
|
raise self.server.error(msg) from None
|
||||||
|
self.state = state
|
||||||
|
|
||||||
|
async def set_power(self, state):
|
||||||
|
try:
|
||||||
|
res = await self._send_homeassistant_command(state)
|
||||||
|
state = res[0][f"state"]
|
||||||
|
except Exception:
|
||||||
|
self.state = "error"
|
||||||
|
msg = f"Error Setting Device Status: {self.name} to {state}"
|
||||||
|
logging.exception(msg)
|
||||||
|
raise self.server.error(msg) from None
|
||||||
|
self.state = state
|
||||||
|
|
||||||
# The power component has multiple configuration sections
|
# The power component has multiple configuration sections
|
||||||
def load_component_multi(config):
|
def load_component_multi(config):
|
||||||
return PrinterPower(config)
|
return PrinterPower(config)
|
||||||
|
|
Loading…
Reference in New Issue