power: add RF transmitter support
Signed-off: Daniel Bauer <github@dbauer.me>
This commit is contained in:
parent
86764657cf
commit
c3f1b290f8
|
@ -190,7 +190,7 @@ gcode:
|
||||||
```
|
```
|
||||||
|
|
||||||
## `[power]`
|
## `[power]`
|
||||||
Enables device power control. Currently GPIO (relays), TPLink Smartplug,
|
Enables device power control. Currently GPIO (relays), RF transmitter, TPLink Smartplug,
|
||||||
and Tasmota (via http) devices, HomeAssistant switch are supported.
|
and Tasmota (via http) devices, HomeAssistant switch are supported.
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
|
@ -198,7 +198,7 @@ and Tasmota (via http) devices, HomeAssistant switch are supported.
|
||||||
|
|
||||||
[power device_name]
|
[power device_name]
|
||||||
type: gpio
|
type: gpio
|
||||||
# The type of device. Can be either gpio, tplink_smartplug, tasmota
|
# The type of device. Can be either gpio, rf, tplink_smartplug, tasmota
|
||||||
# shelly, homeseer, homeassistant, or loxonev1.
|
# shelly, homeseer, homeassistant, or loxonev1.
|
||||||
# This parameter must be provided.
|
# This parameter must be provided.
|
||||||
off_when_shutdown: False
|
off_when_shutdown: False
|
||||||
|
@ -217,7 +217,7 @@ restart_delay: 1.
|
||||||
# If "restart_klipper_when_powered" is set, this option specifies the amount
|
# If "restart_klipper_when_powered" is set, this option specifies the amount
|
||||||
# of time (in seconds) to delay the restart. Default is 1 second.
|
# of time (in seconds) to delay the restart. Default is 1 second.
|
||||||
pin: gpiochip0/gpio26
|
pin: gpiochip0/gpio26
|
||||||
# The pin to use for GPIO devices. The chip is optional, if left out
|
# The pin to use for GPIO and RF devices. The chip is optional, if left out
|
||||||
# then the module will default to gpiochip0. If one wishes to invert
|
# then the module will default to gpiochip0. If one wishes to invert
|
||||||
# the signal, a "!" may be prefixed to the pin. Valid examples:
|
# the signal, a "!" may be prefixed to the pin. Valid examples:
|
||||||
# gpiochip0/gpio26
|
# gpiochip0/gpio26
|
||||||
|
@ -297,6 +297,12 @@ output_id:
|
||||||
# The output_id is the name of a programmed output, virtual input or virtual
|
# The output_id is the name of a programmed output, virtual input or virtual
|
||||||
# output in the loxone config his output_id (name) may only be used once in
|
# output in the loxone config his output_id (name) may only be used once in
|
||||||
# the loxone config
|
# the loxone config
|
||||||
|
on_code:
|
||||||
|
off_code:
|
||||||
|
# The above options are used for "rf" devices. The
|
||||||
|
# codes should be valid binary codes that are send via the RF transmitter.
|
||||||
|
# For example: 1011.
|
||||||
|
|
||||||
```
|
```
|
||||||
Below are some potential examples:
|
Below are some potential examples:
|
||||||
```ini
|
```ini
|
||||||
|
@ -559,4 +565,4 @@ default_qos: 0
|
||||||
api_qos:
|
api_qos:
|
||||||
# The QOS level to use for the API topics. If not provided, the
|
# The QOS level to use for the API topics. If not provided, the
|
||||||
# value specified by "default_qos" will be used.
|
# value specified by "default_qos" will be used.
|
||||||
```
|
```
|
||||||
|
|
|
@ -12,6 +12,7 @@ import json
|
||||||
import struct
|
import struct
|
||||||
import socket
|
import socket
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import time
|
||||||
from tornado.iostream import IOStream
|
from tornado.iostream import IOStream
|
||||||
from tornado.httpclient import AsyncHTTPClient
|
from tornado.httpclient import AsyncHTTPClient
|
||||||
from tornado.escape import json_decode
|
from tornado.escape import json_decode
|
||||||
|
@ -68,7 +69,8 @@ class PrinterPower:
|
||||||
"shelly": Shelly,
|
"shelly": Shelly,
|
||||||
"homeseer": HomeSeer,
|
"homeseer": HomeSeer,
|
||||||
"homeassistant": HomeAssistant,
|
"homeassistant": HomeAssistant,
|
||||||
"loxonev1": Loxonev1
|
"loxonev1": Loxonev1,
|
||||||
|
"rf": RFDevice
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
for section in prefix_sections:
|
for section in prefix_sections:
|
||||||
|
@ -79,7 +81,7 @@ class PrinterPower:
|
||||||
if dev_class is None:
|
if dev_class is None:
|
||||||
raise config.error(f"Unsupported Device Type: {dev_type}")
|
raise config.error(f"Unsupported Device Type: {dev_type}")
|
||||||
dev = dev_class(cfg)
|
dev = dev_class(cfg)
|
||||||
if isinstance(dev, GpioDevice):
|
if isinstance(dev, GpioDevice) or isinstance(dev, RFDevice):
|
||||||
if not HAS_GPIOD:
|
if not HAS_GPIOD:
|
||||||
continue
|
continue
|
||||||
dev.configure_line(cfg, self.chip_factory)
|
dev.configure_line(cfg, self.chip_factory)
|
||||||
|
@ -470,6 +472,53 @@ class GpioDevice(PowerDevice):
|
||||||
def close(self) -> None:
|
def close(self) -> None:
|
||||||
self.line.release()
|
self.line.release()
|
||||||
|
|
||||||
|
class RFDevice(GpioDevice):
|
||||||
|
|
||||||
|
# Protocol definition
|
||||||
|
# [1, 3] means HIGH is set for 1x pulse_len and LOW for 3x pulse_len
|
||||||
|
ZERO_BIT = [1, 3] # zero bit
|
||||||
|
ONE_BIT = [3, 1] # one bit
|
||||||
|
SYNC_BIT = [1, 31] # sync between
|
||||||
|
PULSE_LEN = 0.00035 # length of a single pulse
|
||||||
|
RETRIES = 10 # send the code this many times
|
||||||
|
|
||||||
|
def __init__(self, config: ConfigHelper):
|
||||||
|
super().__init__(config)
|
||||||
|
self.on = config.get("on_code").zfill(24)
|
||||||
|
self.off = config.get("off_code").zfill(24)
|
||||||
|
|
||||||
|
def initialize(self) -> None:
|
||||||
|
self.set_power("on" if self.initial_state else "off")
|
||||||
|
|
||||||
|
def _transmit_digit(self, waveform) -> None:
|
||||||
|
self.line.set_value(1)
|
||||||
|
time.sleep(waveform[0]*RFDevice.PULSE_LEN)
|
||||||
|
self.line.set_value(0)
|
||||||
|
time.sleep(waveform[1]*RFDevice.PULSE_LEN)
|
||||||
|
|
||||||
|
def _transmit_code(self, code) -> None:
|
||||||
|
for _ in range(RFDevice.RETRIES):
|
||||||
|
for i in code:
|
||||||
|
if i == "1":
|
||||||
|
self._transmit_digit(RFDevice.ONE_BIT)
|
||||||
|
elif i == "0":
|
||||||
|
self._transmit_digit(RFDevice.ZERO_BIT)
|
||||||
|
self._transmit_digit(RFDevice.SYNC_BIT)
|
||||||
|
|
||||||
|
def set_power(self, state) -> None:
|
||||||
|
try:
|
||||||
|
if state == "on":
|
||||||
|
code = self.on
|
||||||
|
else:
|
||||||
|
code = self.off
|
||||||
|
self._transmit_code(code)
|
||||||
|
except Exception:
|
||||||
|
self.state = "error"
|
||||||
|
msg = f"Error Toggling Device Power: {self.name}"
|
||||||
|
logging.exception(msg)
|
||||||
|
raise self.server.error(msg) from None
|
||||||
|
self.state = state
|
||||||
|
|
||||||
|
|
||||||
# This implementation based off the work tplink_smartplug
|
# This implementation based off the work tplink_smartplug
|
||||||
# script by Lubomir Stroetmann available at:
|
# script by Lubomir Stroetmann available at:
|
||||||
|
|
Loading…
Reference in New Issue