1 """Support for Arduino-compatible Microcontrollers through Firmata."""
6 import voluptuous
as vol
18 EVENT_HOMEASSISTANT_STOP,
24 from .board
import FirmataBoard
26 CONF_ARDUINO_INSTANCE_ID,
33 CONF_SAMPLING_INTERVAL,
34 CONF_SERIAL_BAUD_RATE,
46 _LOGGER = logging.getLogger(__name__)
48 DATA_CONFIGS =
"board_configs"
50 ANALOG_PIN_SCHEMA = vol.All(cv.string, vol.Match(
r"^A[0-9]+$"))
52 SWITCH_SCHEMA = vol.Schema(
54 vol.Required(CONF_NAME): cv.string,
56 vol.Required(CONF_PIN): vol.Any(cv.positive_int, ANALOG_PIN_SCHEMA),
57 vol.Required(CONF_PIN_MODE): PIN_MODE_OUTPUT,
58 vol.Optional(CONF_INITIAL_STATE, default=
False): cv.boolean,
59 vol.Optional(CONF_NEGATE_STATE, default=
False): cv.boolean,
64 LIGHT_SCHEMA = vol.Schema(
66 vol.Required(CONF_NAME): cv.string,
68 vol.Required(CONF_PIN): vol.Any(cv.positive_int, ANALOG_PIN_SCHEMA),
69 vol.Required(CONF_PIN_MODE): PIN_MODE_PWM,
70 vol.Optional(CONF_INITIAL_STATE, default=0): cv.positive_int,
71 vol.Optional(CONF_MINIMUM, default=0): cv.positive_int,
72 vol.Optional(CONF_MAXIMUM, default=255): cv.positive_int,
77 BINARY_SENSOR_SCHEMA = vol.Schema(
79 vol.Required(CONF_NAME): cv.string,
81 vol.Required(CONF_PIN): vol.Any(cv.positive_int, ANALOG_PIN_SCHEMA),
82 vol.Required(CONF_PIN_MODE): vol.Any(PIN_MODE_INPUT, PIN_MODE_PULLUP),
83 vol.Optional(CONF_NEGATE_STATE, default=
False): cv.boolean,
88 SENSOR_SCHEMA = vol.Schema(
90 vol.Required(CONF_NAME): cv.string,
92 vol.Required(CONF_PIN): ANALOG_PIN_SCHEMA,
93 vol.Required(CONF_PIN_MODE): PIN_MODE_ANALOG,
96 vol.Optional(CONF_DIFFERENTIAL, default=40): vol.All(
97 cv.positive_int, vol.Range(min=1)
103 BOARD_CONFIG_SCHEMA = vol.Schema(
105 vol.Required(CONF_SERIAL_PORT): cv.string,
106 vol.Optional(CONF_SERIAL_BAUD_RATE): cv.positive_int,
107 vol.Optional(CONF_ARDUINO_INSTANCE_ID): cv.positive_int,
108 vol.Optional(CONF_ARDUINO_WAIT): cv.positive_int,
109 vol.Optional(CONF_SLEEP_TUNE): vol.All(
110 vol.Coerce(float), vol.Range(min=0.0001)
112 vol.Optional(CONF_SAMPLING_INTERVAL): cv.positive_int,
113 vol.Optional(CONF_SWITCHES): [SWITCH_SCHEMA],
114 vol.Optional(CONF_LIGHTS): [LIGHT_SCHEMA],
115 vol.Optional(CONF_BINARY_SENSORS): [BINARY_SENSOR_SCHEMA],
116 vol.Optional(CONF_SENSORS): [SENSOR_SCHEMA],
121 CONFIG_SCHEMA = vol.Schema(
122 {DOMAIN: vol.All(cv.ensure_list, [BOARD_CONFIG_SCHEMA])}, extra=vol.ALLOW_EXTRA
126 async
def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
127 """Set up the Firmata domain."""
129 if hass.config_entries.async_entries(DOMAIN):
130 for entry
in hass.config_entries.async_entries(DOMAIN):
132 for board
in config[DOMAIN]:
133 if entry.data[CONF_SERIAL_PORT] == board[CONF_SERIAL_PORT]:
137 await hass.config_entries.async_remove(entry.entry_id)
140 for board
in config[DOMAIN]:
141 firmata_config = copy(board)
142 existing_entry =
False
143 for entry
in hass.config_entries.async_entries(DOMAIN):
144 if board[CONF_SERIAL_PORT] == entry.data[CONF_SERIAL_PORT]:
145 existing_entry =
True
146 firmata_config[CONF_NAME] = entry.data[CONF_NAME]
147 hass.config_entries.async_update_entry(entry, data=firmata_config)
149 if not existing_entry:
150 hass.async_create_task(
151 hass.config_entries.flow.async_init(
153 context={
"source": SOURCE_IMPORT},
162 """Set up a Firmata board for a config entry."""
163 if DOMAIN
not in hass.data:
164 hass.data[DOMAIN] = {}
167 "Setting up Firmata id %s, name %s, config %s",
168 config_entry.entry_id,
169 config_entry.data[CONF_NAME],
175 if not await board.async_setup():
178 hass.data[DOMAIN][config_entry.entry_id] = board
180 async
def handle_shutdown(event) -> None:
181 """Handle shutdown of board when Home Assistant shuts down."""
183 if config_entry.entry_id
in hass.data[DOMAIN]:
184 await board.async_reset()
186 config_entry.async_on_unload(
187 hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, handle_shutdown)
190 device_registry = dr.async_get(hass)
191 device_registry.async_get_or_create(
192 config_entry_id=config_entry.entry_id,
194 identifiers={(DOMAIN, board.name)},
195 manufacturer=FIRMATA_MANUFACTURER,
197 sw_version=board.firmware_version,
200 await hass.config_entries.async_forward_entry_setups(
204 for conf, platform
in CONF_PLATFORM_MAP.items()
205 if conf
in config_entry.data
212 """Shutdown and close a Firmata board for a config entry."""
213 _LOGGER.debug(
"Closing Firmata board %s", config_entry.data[CONF_NAME])
214 results: list[bool] = []
217 for conf, platform
in CONF_PLATFORM_MAP.items()
218 if conf
in config_entry.data
221 await hass.config_entries.async_unload_platforms(config_entry, platforms)
223 results.append(await hass.data[DOMAIN].pop(config_entry.entry_id).async_reset())
225 return False not in results
bool async_setup(HomeAssistant hass, ConfigType config)
bool async_setup_entry(HomeAssistant hass, ConfigEntry config_entry)
bool async_unload_entry(HomeAssistant hass, ConfigEntry config_entry)