Firmata analog input, PWM/analog output, deprecate arduino (#40369)
* firmata analog input * firmata pwm/analog out, use more HA const * firmata update pymata to 1.19 * deprecate arduino, firmata supersedes it * firmata sensor diff min, pull review quality changes * firmata condense platform setup into loop
This commit is contained in:
parent
50b727ba83
commit
0582bf7746
13 changed files with 379 additions and 57 deletions
|
@ -269,7 +269,9 @@ omit =
|
|||
homeassistant/components/firmata/board.py
|
||||
homeassistant/components/firmata/const.py
|
||||
homeassistant/components/firmata/entity.py
|
||||
homeassistant/components/firmata/light.py
|
||||
homeassistant/components/firmata/pin.py
|
||||
homeassistant/components/firmata/sensor.py
|
||||
homeassistant/components/firmata/switch.py
|
||||
homeassistant/components/fitbit/sensor.py
|
||||
homeassistant/components/fixer/sensor.py
|
||||
|
|
|
@ -23,6 +23,12 @@ CONFIG_SCHEMA = vol.Schema(
|
|||
|
||||
def setup(hass, config):
|
||||
"""Set up the Arduino component."""
|
||||
_LOGGER.warning(
|
||||
"The %s integration has been deprecated. Please move your "
|
||||
"configuration to the firmata integration. "
|
||||
"https://www.home-assistant.io/integrations/firmata",
|
||||
DOMAIN,
|
||||
)
|
||||
|
||||
port = config[DOMAIN][CONF_PORT]
|
||||
|
||||
|
|
|
@ -6,7 +6,17 @@ import logging
|
|||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_NAME, EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.const import (
|
||||
CONF_BINARY_SENSORS,
|
||||
CONF_LIGHTS,
|
||||
CONF_MAXIMUM,
|
||||
CONF_MINIMUM,
|
||||
CONF_NAME,
|
||||
CONF_PIN,
|
||||
CONF_SENSORS,
|
||||
CONF_SWITCHES,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv, device_registry as dr
|
||||
|
||||
|
@ -14,21 +24,22 @@ from .board import FirmataBoard
|
|||
from .const import (
|
||||
CONF_ARDUINO_INSTANCE_ID,
|
||||
CONF_ARDUINO_WAIT,
|
||||
CONF_BINARY_SENSORS,
|
||||
CONF_DIFFERENTIAL,
|
||||
CONF_INITIAL_STATE,
|
||||
CONF_NEGATE_STATE,
|
||||
CONF_PIN,
|
||||
CONF_PIN_MODE,
|
||||
CONF_PLATFORM_MAP,
|
||||
CONF_SAMPLING_INTERVAL,
|
||||
CONF_SERIAL_BAUD_RATE,
|
||||
CONF_SERIAL_PORT,
|
||||
CONF_SLEEP_TUNE,
|
||||
CONF_SWITCHES,
|
||||
DOMAIN,
|
||||
FIRMATA_MANUFACTURER,
|
||||
PIN_MODE_ANALOG,
|
||||
PIN_MODE_INPUT,
|
||||
PIN_MODE_OUTPUT,
|
||||
PIN_MODE_PULLUP,
|
||||
PIN_MODE_PWM,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -40,8 +51,8 @@ ANALOG_PIN_SCHEMA = vol.All(cv.string, vol.Match(r"^A[0-9]+$"))
|
|||
SWITCH_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_NAME): cv.string,
|
||||
# Both digital and analog pins may be used as digital output
|
||||
vol.Required(CONF_PIN): vol.Any(cv.positive_int, ANALOG_PIN_SCHEMA),
|
||||
# will be analog mode in future too
|
||||
vol.Required(CONF_PIN_MODE): PIN_MODE_OUTPUT,
|
||||
vol.Optional(CONF_INITIAL_STATE, default=False): cv.boolean,
|
||||
vol.Optional(CONF_NEGATE_STATE, default=False): cv.boolean,
|
||||
|
@ -49,17 +60,45 @@ SWITCH_SCHEMA = vol.Schema(
|
|||
required=True,
|
||||
)
|
||||
|
||||
LIGHT_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_NAME): cv.string,
|
||||
# Both digital and analog pins may be used as PWM/analog output
|
||||
vol.Required(CONF_PIN): vol.Any(cv.positive_int, ANALOG_PIN_SCHEMA),
|
||||
vol.Required(CONF_PIN_MODE): PIN_MODE_PWM,
|
||||
vol.Optional(CONF_INITIAL_STATE, default=0): cv.positive_int,
|
||||
vol.Optional(CONF_MINIMUM, default=0): cv.positive_int,
|
||||
vol.Optional(CONF_MAXIMUM, default=255): cv.positive_int,
|
||||
},
|
||||
required=True,
|
||||
)
|
||||
|
||||
BINARY_SENSOR_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_NAME): cv.string,
|
||||
# Both digital and analog pins may be used as digital input
|
||||
vol.Required(CONF_PIN): vol.Any(cv.positive_int, ANALOG_PIN_SCHEMA),
|
||||
# will be analog mode in future too
|
||||
vol.Required(CONF_PIN_MODE): vol.Any(PIN_MODE_INPUT, PIN_MODE_PULLUP),
|
||||
vol.Optional(CONF_NEGATE_STATE, default=False): cv.boolean,
|
||||
},
|
||||
required=True,
|
||||
)
|
||||
|
||||
SENSOR_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_NAME): cv.string,
|
||||
# Currently only analog input sensor is implemented
|
||||
vol.Required(CONF_PIN): ANALOG_PIN_SCHEMA,
|
||||
vol.Required(CONF_PIN_MODE): PIN_MODE_ANALOG,
|
||||
# Default differential is 40 to avoid a flood of messages on initial setup
|
||||
# in case pin is unplugged. Firmata responds really really fast
|
||||
vol.Optional(CONF_DIFFERENTIAL, default=40): vol.All(
|
||||
cv.positive_int, vol.Range(min=1)
|
||||
),
|
||||
},
|
||||
required=True,
|
||||
)
|
||||
|
||||
BOARD_CONFIG_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_SERIAL_PORT): cv.string,
|
||||
|
@ -71,7 +110,9 @@ BOARD_CONFIG_SCHEMA = vol.Schema(
|
|||
),
|
||||
vol.Optional(CONF_SAMPLING_INTERVAL): cv.positive_int,
|
||||
vol.Optional(CONF_SWITCHES): [SWITCH_SCHEMA],
|
||||
vol.Optional(CONF_LIGHTS): [LIGHT_SCHEMA],
|
||||
vol.Optional(CONF_BINARY_SENSORS): [BINARY_SENSOR_SCHEMA],
|
||||
vol.Optional(CONF_SENSORS): [SENSOR_SCHEMA],
|
||||
},
|
||||
required=True,
|
||||
)
|
||||
|
@ -155,14 +196,11 @@ async def async_setup_entry(
|
|||
sw_version=board.firmware_version,
|
||||
)
|
||||
|
||||
if CONF_BINARY_SENSORS in config_entry.data:
|
||||
hass.async_create_task(
|
||||
hass.config_entries.async_forward_entry_setup(config_entry, "binary_sensor")
|
||||
)
|
||||
if CONF_SWITCHES in config_entry.data:
|
||||
hass.async_create_task(
|
||||
hass.config_entries.async_forward_entry_setup(config_entry, "switch")
|
||||
)
|
||||
for (conf, platform) in CONF_PLATFORM_MAP.items():
|
||||
if conf in config_entry.data:
|
||||
hass.async_create_task(
|
||||
hass.config_entries.async_forward_entry_setup(config_entry, platform)
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
|
@ -173,16 +211,11 @@ async def async_unload_entry(
|
|||
_LOGGER.debug("Closing Firmata board %s", config_entry.data[CONF_NAME])
|
||||
|
||||
unload_entries = []
|
||||
if CONF_BINARY_SENSORS in config_entry.data:
|
||||
unload_entries.append(
|
||||
hass.config_entries.async_forward_entry_unload(
|
||||
config_entry, "binary_sensor"
|
||||
for (conf, platform) in CONF_PLATFORM_MAP.items():
|
||||
if conf in config_entry.data:
|
||||
unload_entries.append(
|
||||
hass.config_entries.async_forward_entry_unload(config_entry, platform)
|
||||
)
|
||||
)
|
||||
if CONF_SWITCHES in config_entry.data:
|
||||
unload_entries.append(
|
||||
hass.config_entries.async_forward_entry_unload(config_entry, "switch")
|
||||
)
|
||||
results = []
|
||||
if unload_entries:
|
||||
results = await asyncio.gather(*unload_entries)
|
||||
|
|
|
@ -4,10 +4,10 @@ import logging
|
|||
|
||||
from homeassistant.components.binary_sensor import BinarySensorEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_NAME
|
||||
from homeassistant.const import CONF_NAME, CONF_PIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import CONF_NEGATE_STATE, CONF_PIN, CONF_PIN_MODE, DOMAIN
|
||||
from .const import CONF_NEGATE_STATE, CONF_PIN_MODE, DOMAIN
|
||||
from .entity import FirmataPinEntity
|
||||
from .pin import FirmataBinaryDigitalInput, FirmataPinUsedException
|
||||
|
||||
|
@ -30,7 +30,7 @@ async def async_setup_entry(
|
|||
api.setup()
|
||||
except FirmataPinUsedException:
|
||||
_LOGGER.error(
|
||||
"Could not setup binary sensor on pin %s since pin already in use.",
|
||||
"Could not setup binary sensor on pin %s since pin already in use",
|
||||
binary_sensor[CONF_PIN],
|
||||
)
|
||||
continue
|
||||
|
|
|
@ -5,17 +5,23 @@ from typing import Union
|
|||
from pymata_express.pymata_express import PymataExpress
|
||||
from pymata_express.pymata_express_serial import serial
|
||||
|
||||
from homeassistant.const import CONF_NAME
|
||||
from homeassistant.const import (
|
||||
CONF_BINARY_SENSORS,
|
||||
CONF_LIGHTS,
|
||||
CONF_NAME,
|
||||
CONF_SENSORS,
|
||||
CONF_SWITCHES,
|
||||
)
|
||||
|
||||
from .const import (
|
||||
CONF_ARDUINO_INSTANCE_ID,
|
||||
CONF_ARDUINO_WAIT,
|
||||
CONF_BINARY_SENSORS,
|
||||
CONF_SAMPLING_INTERVAL,
|
||||
CONF_SERIAL_BAUD_RATE,
|
||||
CONF_SERIAL_PORT,
|
||||
CONF_SLEEP_TUNE,
|
||||
CONF_SWITCHES,
|
||||
PIN_TYPE_ANALOG,
|
||||
PIN_TYPE_DIGITAL,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -34,13 +40,19 @@ class FirmataBoard:
|
|||
self.protocol_version = None
|
||||
self.name = self.config[CONF_NAME]
|
||||
self.switches = []
|
||||
self.lights = []
|
||||
self.binary_sensors = []
|
||||
self.sensors = []
|
||||
self.used_pins = []
|
||||
|
||||
if CONF_SWITCHES in self.config:
|
||||
self.switches = self.config[CONF_SWITCHES]
|
||||
if CONF_LIGHTS in self.config:
|
||||
self.lights = self.config[CONF_LIGHTS]
|
||||
if CONF_BINARY_SENSORS in self.config:
|
||||
self.binary_sensors = self.config[CONF_BINARY_SENSORS]
|
||||
if CONF_SENSORS in self.config:
|
||||
self.sensors = self.config[CONF_SENSORS]
|
||||
|
||||
async def async_setup(self, tries=0) -> bool:
|
||||
"""Set up a Firmata instance."""
|
||||
|
@ -109,11 +121,11 @@ board %s: %s",
|
|||
def get_pin_type(self, pin: FirmataPinType) -> tuple:
|
||||
"""Return the type and Firmata location of a pin on the board."""
|
||||
if isinstance(pin, str):
|
||||
pin_type = "analog"
|
||||
pin_type = PIN_TYPE_ANALOG
|
||||
firmata_pin = int(pin[1:])
|
||||
firmata_pin += self.api.first_analog_pin
|
||||
else:
|
||||
pin_type = "digital"
|
||||
pin_type = PIN_TYPE_DIGITAL
|
||||
firmata_pin = pin
|
||||
return (pin_type, firmata_pin)
|
||||
|
||||
|
|
|
@ -1,24 +1,35 @@
|
|||
"""Constants for the Firmata component."""
|
||||
import logging
|
||||
|
||||
LOGGER = logging.getLogger(__package__)
|
||||
from homeassistant.const import (
|
||||
CONF_BINARY_SENSORS,
|
||||
CONF_LIGHTS,
|
||||
CONF_SENSORS,
|
||||
CONF_SWITCHES,
|
||||
)
|
||||
|
||||
CONF_ARDUINO_INSTANCE_ID = "arduino_instance_id"
|
||||
CONF_ARDUINO_WAIT = "arduino_wait"
|
||||
CONF_BINARY_SENSORS = "binary_sensors"
|
||||
CONF_DIFFERENTIAL = "differential"
|
||||
CONF_INITIAL_STATE = "initial"
|
||||
CONF_NAME = "name"
|
||||
CONF_NEGATE_STATE = "negate"
|
||||
CONF_PIN = "pin"
|
||||
CONF_PINS = "pins"
|
||||
CONF_PIN_MODE = "pin_mode"
|
||||
PIN_MODE_ANALOG = "ANALOG"
|
||||
PIN_MODE_OUTPUT = "OUTPUT"
|
||||
PIN_MODE_PWM = "PWM"
|
||||
PIN_MODE_INPUT = "INPUT"
|
||||
PIN_MODE_PULLUP = "PULLUP"
|
||||
PIN_TYPE_ANALOG = 1
|
||||
PIN_TYPE_DIGITAL = 0
|
||||
CONF_SAMPLING_INTERVAL = "sampling_interval"
|
||||
CONF_SERIAL_BAUD_RATE = "serial_baud_rate"
|
||||
CONF_SERIAL_PORT = "serial_port"
|
||||
CONF_SLEEP_TUNE = "sleep_tune"
|
||||
CONF_SWITCHES = "switches"
|
||||
DOMAIN = "firmata"
|
||||
FIRMATA_MANUFACTURER = "Firmata"
|
||||
CONF_PLATFORM_MAP = {
|
||||
CONF_BINARY_SENSORS: "binary_sensor",
|
||||
CONF_LIGHTS: "light",
|
||||
CONF_SENSORS: "sensor",
|
||||
CONF_SWITCHES: "switch",
|
||||
}
|
||||
|
|
98
homeassistant/components/firmata/light.py
Normal file
98
homeassistant/components/firmata/light.py
Normal file
|
@ -0,0 +1,98 @@
|
|||
"""Support for Firmata light output."""
|
||||
|
||||
import logging
|
||||
from typing import Type
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
SUPPORT_BRIGHTNESS,
|
||||
LightEntity,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_MAXIMUM, CONF_MINIMUM, CONF_NAME, CONF_PIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .board import FirmataPinType
|
||||
from .const import CONF_INITIAL_STATE, CONF_PIN_MODE, DOMAIN
|
||||
from .entity import FirmataPinEntity
|
||||
from .pin import FirmataBoardPin, FirmataPinUsedException, FirmataPWMOutput
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities
|
||||
) -> None:
|
||||
"""Set up the Firmata lights."""
|
||||
new_entities = []
|
||||
|
||||
board = hass.data[DOMAIN][config_entry.entry_id]
|
||||
for light in board.lights:
|
||||
pin = light[CONF_PIN]
|
||||
pin_mode = light[CONF_PIN_MODE]
|
||||
initial = light[CONF_INITIAL_STATE]
|
||||
minimum = light[CONF_MINIMUM]
|
||||
maximum = light[CONF_MAXIMUM]
|
||||
api = FirmataPWMOutput(board, pin, pin_mode, initial, minimum, maximum)
|
||||
try:
|
||||
api.setup()
|
||||
except FirmataPinUsedException:
|
||||
_LOGGER.error(
|
||||
"Could not setup light on pin %s since pin already in use",
|
||||
light[CONF_PIN],
|
||||
)
|
||||
continue
|
||||
name = light[CONF_NAME]
|
||||
light_entity = FirmataLight(api, config_entry, name, pin)
|
||||
new_entities.append(light_entity)
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class FirmataLight(FirmataPinEntity, LightEntity):
|
||||
"""Representation of a light on a Firmata board."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
api: Type[FirmataBoardPin],
|
||||
config_entry: ConfigEntry,
|
||||
name: str,
|
||||
pin: FirmataPinType,
|
||||
):
|
||||
"""Initialize the light pin entity."""
|
||||
super().__init__(api, config_entry, name, pin)
|
||||
|
||||
# Default first turn on to max
|
||||
self._last_on_level = 255
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Set up a light."""
|
||||
await self._api.start_pin()
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return true if light is on."""
|
||||
return self._api.state > 0
|
||||
|
||||
@property
|
||||
def brightness(self) -> int:
|
||||
"""Return the brightness of the light."""
|
||||
return self._api.state
|
||||
|
||||
@property
|
||||
def supported_features(self) -> int:
|
||||
"""Flag supported features."""
|
||||
return SUPPORT_BRIGHTNESS
|
||||
|
||||
async def async_turn_on(self, **kwargs) -> None:
|
||||
"""Turn on light."""
|
||||
level = kwargs.get(ATTR_BRIGHTNESS, self._last_on_level)
|
||||
await self._api.set_level(level)
|
||||
self.async_write_ha_state()
|
||||
self._last_on_level = level
|
||||
|
||||
async def async_turn_off(self, **kwargs) -> None:
|
||||
"""Turn off light."""
|
||||
await self._api.set_level(0)
|
||||
self.async_write_ha_state()
|
|
@ -4,7 +4,7 @@
|
|||
"config_flow": false,
|
||||
"documentation": "https://www.home-assistant.io/integrations/firmata",
|
||||
"requirements": [
|
||||
"pymata-express==1.13"
|
||||
"pymata-express==1.19"
|
||||
],
|
||||
"codeowners": [
|
||||
"@DaAwesomeP"
|
||||
|
|
|
@ -2,10 +2,8 @@
|
|||
import logging
|
||||
from typing import Callable
|
||||
|
||||
from homeassistant.core import callback
|
||||
|
||||
from .board import FirmataBoard, FirmataPinType
|
||||
from .const import PIN_MODE_INPUT, PIN_MODE_PULLUP
|
||||
from .const import PIN_MODE_INPUT, PIN_MODE_PULLUP, PIN_TYPE_ANALOG
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -25,6 +23,10 @@ class FirmataBoardPin:
|
|||
self._pin_type, self._firmata_pin = self.board.get_pin_type(self._pin)
|
||||
self._state = None
|
||||
|
||||
if self._pin_type == PIN_TYPE_ANALOG:
|
||||
# Pymata wants the analog pin formatted as the # from "A#"
|
||||
self._analog_pin = int(self._pin[1:])
|
||||
|
||||
def setup(self):
|
||||
"""Set up a pin and make sure it is valid."""
|
||||
if not self.board.mark_pin_used(self._pin):
|
||||
|
@ -85,6 +87,53 @@ class FirmataBinaryDigitalOutput(FirmataBoardPin):
|
|||
self._state = False
|
||||
|
||||
|
||||
class FirmataPWMOutput(FirmataBoardPin):
|
||||
"""Representation of a Firmata PWM/analog Output Pin."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
board: FirmataBoard,
|
||||
pin: FirmataPinType,
|
||||
pin_mode: str,
|
||||
initial: bool,
|
||||
minimum: int,
|
||||
maximum: int,
|
||||
):
|
||||
"""Initialize the PWM/analog output pin."""
|
||||
self._initial = initial
|
||||
self._min = minimum
|
||||
self._max = maximum
|
||||
self._range = self._max - self._min
|
||||
super().__init__(board, pin, pin_mode)
|
||||
|
||||
async def start_pin(self) -> None:
|
||||
"""Set initial state on a pin."""
|
||||
_LOGGER.debug(
|
||||
"Setting initial state for PWM/analog output pin %s on board %s to %d",
|
||||
self._pin,
|
||||
self.board.name,
|
||||
self._initial,
|
||||
)
|
||||
api = self.board.api
|
||||
await api.set_pin_mode_pwm_output(self._firmata_pin)
|
||||
|
||||
new_pin_state = round((self._initial * self._range) / 255) + self._min
|
||||
await api.pwm_write(self._firmata_pin, new_pin_state)
|
||||
self._state = self._initial
|
||||
|
||||
@property
|
||||
def state(self) -> int:
|
||||
"""Return PWM/analog state."""
|
||||
return self._state
|
||||
|
||||
async def set_level(self, level: int) -> None:
|
||||
"""Set PWM/analog output."""
|
||||
_LOGGER.debug("Setting PWM/analog output on pin %s to %d", self._pin, level)
|
||||
new_pin_state = round((level * self._range) / 255) + self._min
|
||||
await self.board.api.pwm_write(self._firmata_pin, new_pin_state)
|
||||
self._state = level
|
||||
|
||||
|
||||
class FirmataBinaryDigitalInput(FirmataBoardPin):
|
||||
"""Representation of a Firmata Digital Input Pin."""
|
||||
|
||||
|
@ -99,7 +148,7 @@ class FirmataBinaryDigitalInput(FirmataBoardPin):
|
|||
async def start_pin(self, forward_callback: Callable[[], None]) -> None:
|
||||
"""Get initial state and start reporting a pin."""
|
||||
_LOGGER.debug(
|
||||
"Starting reporting updates for input pin %s on board %s",
|
||||
"Starting reporting updates for digital input pin %s on board %s",
|
||||
self._pin,
|
||||
self.board.name,
|
||||
)
|
||||
|
@ -133,7 +182,6 @@ class FirmataBinaryDigitalInput(FirmataBoardPin):
|
|||
"""Return true if digital input is on."""
|
||||
return self._state
|
||||
|
||||
@callback
|
||||
async def latch_callback(self, data: list) -> None:
|
||||
"""Update pin state on callback."""
|
||||
if data[1] != self._firmata_pin:
|
||||
|
@ -151,3 +199,65 @@ class FirmataBinaryDigitalInput(FirmataBoardPin):
|
|||
return
|
||||
self._state = new_state
|
||||
self._forward_callback()
|
||||
|
||||
|
||||
class FirmataAnalogInput(FirmataBoardPin):
|
||||
"""Representation of a Firmata Analog Input Pin."""
|
||||
|
||||
def __init__(
|
||||
self, board: FirmataBoard, pin: FirmataPinType, pin_mode: str, differential: int
|
||||
):
|
||||
"""Initialize the analog input pin."""
|
||||
self._differential = differential
|
||||
self._forward_callback = None
|
||||
super().__init__(board, pin, pin_mode)
|
||||
|
||||
async def start_pin(self, forward_callback: Callable[[], None]) -> None:
|
||||
"""Get initial state and start reporting a pin."""
|
||||
_LOGGER.debug(
|
||||
"Starting reporting updates for analog input pin %s on board %s",
|
||||
self._pin,
|
||||
self.board.name,
|
||||
)
|
||||
self._forward_callback = forward_callback
|
||||
api = self.board.api
|
||||
# Only PIN_MODE_ANALOG_INPUT mode is supported as sensor input
|
||||
await api.set_pin_mode_analog_input(
|
||||
self._analog_pin, self.latch_callback, self._differential
|
||||
)
|
||||
|
||||
self._state = (await self.board.api.analog_read(self._analog_pin))[0]
|
||||
|
||||
self._forward_callback()
|
||||
|
||||
async def stop_pin(self) -> None:
|
||||
"""Stop reporting analog input pin."""
|
||||
_LOGGER.debug(
|
||||
"Stopping reporting updates for analog input pin %s on board %s",
|
||||
self._pin,
|
||||
self.board.name,
|
||||
)
|
||||
api = self.board.api
|
||||
await api.disable_analog_reporting(self._analog_pin)
|
||||
|
||||
@property
|
||||
def state(self) -> int:
|
||||
"""Return sensor state."""
|
||||
return self._state
|
||||
|
||||
async def latch_callback(self, data: list) -> None:
|
||||
"""Update pin state on callback."""
|
||||
if data[1] != self._analog_pin:
|
||||
return
|
||||
_LOGGER.debug(
|
||||
"Received latch %d for analog input pin %s on board %s",
|
||||
data[2],
|
||||
self._pin,
|
||||
self.board.name,
|
||||
)
|
||||
new_state = data[2]
|
||||
if self._state == new_state:
|
||||
_LOGGER.debug("stopping")
|
||||
return
|
||||
self._state = new_state
|
||||
self._forward_callback()
|
||||
|
|
59
homeassistant/components/firmata/sensor.py
Normal file
59
homeassistant/components/firmata/sensor.py
Normal file
|
@ -0,0 +1,59 @@
|
|||
"""Support for Firmata sensor input."""
|
||||
|
||||
import logging
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_NAME, CONF_PIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from .const import CONF_DIFFERENTIAL, CONF_PIN_MODE, DOMAIN
|
||||
from .entity import FirmataPinEntity
|
||||
from .pin import FirmataAnalogInput, FirmataPinUsedException
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities
|
||||
) -> None:
|
||||
"""Set up the Firmata sensors."""
|
||||
new_entities = []
|
||||
|
||||
board = hass.data[DOMAIN][config_entry.entry_id]
|
||||
for sensor in board.sensors:
|
||||
pin = sensor[CONF_PIN]
|
||||
pin_mode = sensor[CONF_PIN_MODE]
|
||||
differential = sensor[CONF_DIFFERENTIAL]
|
||||
api = FirmataAnalogInput(board, pin, pin_mode, differential)
|
||||
try:
|
||||
api.setup()
|
||||
except FirmataPinUsedException:
|
||||
_LOGGER.error(
|
||||
"Could not setup sensor on pin %s since pin already in use",
|
||||
sensor[CONF_PIN],
|
||||
)
|
||||
continue
|
||||
name = sensor[CONF_NAME]
|
||||
sensor_entity = FirmataSensor(api, config_entry, name, pin)
|
||||
new_entities.append(sensor_entity)
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class FirmataSensor(FirmataPinEntity, Entity):
|
||||
"""Representation of a sensor on a Firmata board."""
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Set up a sensor."""
|
||||
await self._api.start_pin(self.async_write_ha_state)
|
||||
|
||||
async def async_will_remove_from_hass(self) -> None:
|
||||
"""Stop reporting a sensor."""
|
||||
await self._api.stop_pin()
|
||||
|
||||
@property
|
||||
def state(self) -> int:
|
||||
"""Return sensor state."""
|
||||
return self._api.state
|
|
@ -4,16 +4,10 @@ import logging
|
|||
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_NAME
|
||||
from homeassistant.const import CONF_NAME, CONF_PIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import (
|
||||
CONF_INITIAL_STATE,
|
||||
CONF_NEGATE_STATE,
|
||||
CONF_PIN,
|
||||
CONF_PIN_MODE,
|
||||
DOMAIN,
|
||||
)
|
||||
from .const import CONF_INITIAL_STATE, CONF_NEGATE_STATE, CONF_PIN_MODE, DOMAIN
|
||||
from .entity import FirmataPinEntity
|
||||
from .pin import FirmataBinaryDigitalOutput, FirmataPinUsedException
|
||||
|
||||
|
@ -37,7 +31,7 @@ async def async_setup_entry(
|
|||
api.setup()
|
||||
except FirmataPinUsedException:
|
||||
_LOGGER.error(
|
||||
"Could not setup switch on pin %s since pin already in use.",
|
||||
"Could not setup switch on pin %s since pin already in use",
|
||||
switch[CONF_PIN],
|
||||
)
|
||||
continue
|
||||
|
@ -55,7 +49,6 @@ class FirmataSwitch(FirmataPinEntity, SwitchEntity):
|
|||
async def async_added_to_hass(self) -> None:
|
||||
"""Set up a switch."""
|
||||
await self._api.start_pin()
|
||||
self.async_write_ha_state()
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
|
@ -64,12 +57,10 @@ class FirmataSwitch(FirmataPinEntity, SwitchEntity):
|
|||
|
||||
async def async_turn_on(self, **kwargs) -> None:
|
||||
"""Turn on switch."""
|
||||
_LOGGER.debug("Turning switch %s on", self._name)
|
||||
await self._api.turn_on()
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_turn_off(self, **kwargs) -> None:
|
||||
"""Turn off switch."""
|
||||
_LOGGER.debug("Turning switch %s off", self._name)
|
||||
await self._api.turn_off()
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -1470,7 +1470,7 @@ pylutron==0.2.5
|
|||
pymailgunner==1.4
|
||||
|
||||
# homeassistant.components.firmata
|
||||
pymata-express==1.13
|
||||
pymata-express==1.19
|
||||
|
||||
# homeassistant.components.mediaroom
|
||||
pymediaroom==0.6.4.1
|
||||
|
|
|
@ -713,7 +713,7 @@ pylutron-caseta==0.6.1
|
|||
pymailgunner==1.4
|
||||
|
||||
# homeassistant.components.firmata
|
||||
pymata-express==1.13
|
||||
pymata-express==1.19
|
||||
|
||||
# homeassistant.components.melcloud
|
||||
pymelcloud==2.5.2
|
||||
|
|
Loading…
Add table
Reference in a new issue