mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
Merge pull request #38964 from home-assistant/rc
This commit is contained in:
commit
740209a81d
@ -52,18 +52,21 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||||||
coordinates=(lat, lon), precip_type=config.get(CONF_PRECIP_TYPE)
|
coordinates=(lat, lon), precip_type=config.get(CONF_PRECIP_TYPE)
|
||||||
)
|
)
|
||||||
|
|
||||||
add_devices([ECCamera(radar_object, config.get(CONF_NAME))], True)
|
add_devices(
|
||||||
|
[ECCamera(radar_object, config.get(CONF_NAME), config[CONF_LOOP])], True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ECCamera(Camera):
|
class ECCamera(Camera):
|
||||||
"""Implementation of an Environment Canada radar camera."""
|
"""Implementation of an Environment Canada radar camera."""
|
||||||
|
|
||||||
def __init__(self, radar_object, camera_name):
|
def __init__(self, radar_object, camera_name, is_loop):
|
||||||
"""Initialize the camera."""
|
"""Initialize the camera."""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.radar_object = radar_object
|
self.radar_object = radar_object
|
||||||
self.camera_name = camera_name
|
self.camera_name = camera_name
|
||||||
|
self.is_loop = is_loop
|
||||||
self.content_type = "image/gif"
|
self.content_type = "image/gif"
|
||||||
self.image = None
|
self.image = None
|
||||||
self.timestamp = None
|
self.timestamp = None
|
||||||
@ -90,7 +93,7 @@ class ECCamera(Camera):
|
|||||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||||
def update(self):
|
def update(self):
|
||||||
"""Update radar image."""
|
"""Update radar image."""
|
||||||
if CONF_LOOP:
|
if self.is_loop:
|
||||||
self.image = self.radar_object.get_loop()
|
self.image = self.radar_object.get_loop()
|
||||||
else:
|
else:
|
||||||
self.image = self.radar_object.get_latest_frame()
|
self.image = self.radar_object.get_latest_frame()
|
||||||
|
@ -235,10 +235,10 @@ class FibaroController:
|
|||||||
scenes = self._client.scenes.list()
|
scenes = self._client.scenes.list()
|
||||||
self._scene_map = {}
|
self._scene_map = {}
|
||||||
for device in scenes:
|
for device in scenes:
|
||||||
if "visible" in device and not device.visible:
|
if "name" not in device or "id" not in device:
|
||||||
continue
|
continue
|
||||||
device.fibaro_controller = self
|
device.fibaro_controller = self
|
||||||
if device.roomID == 0:
|
if "roomID" not in device or device.roomID == 0:
|
||||||
room_name = "Unknown"
|
room_name = "Unknown"
|
||||||
else:
|
else:
|
||||||
room_name = self._room_map[device.roomID].name
|
room_name = self._room_map[device.roomID].name
|
||||||
@ -250,6 +250,7 @@ class FibaroController:
|
|||||||
device.unique_id_str = f"{self.hub_serial}.scene.{device.id}"
|
device.unique_id_str = f"{self.hub_serial}.scene.{device.id}"
|
||||||
self._scene_map[device.id] = device
|
self._scene_map[device.id] = device
|
||||||
self.fibaro_devices["scene"].append(device)
|
self.fibaro_devices["scene"].append(device)
|
||||||
|
_LOGGER.debug("%s scene -> %s", device.ha_id, device)
|
||||||
|
|
||||||
def _read_devices(self):
|
def _read_devices(self):
|
||||||
"""Read and process the device list."""
|
"""Read and process the device list."""
|
||||||
@ -259,8 +260,10 @@ class FibaroController:
|
|||||||
last_climate_parent = None
|
last_climate_parent = None
|
||||||
for device in devices:
|
for device in devices:
|
||||||
try:
|
try:
|
||||||
|
if "name" not in device or "id" not in device:
|
||||||
|
continue
|
||||||
device.fibaro_controller = self
|
device.fibaro_controller = self
|
||||||
if device.roomID == 0:
|
if "roomID" not in device or device.roomID == 0:
|
||||||
room_name = "Unknown"
|
room_name = "Unknown"
|
||||||
else:
|
else:
|
||||||
room_name = self._room_map[device.roomID].name
|
room_name = self._room_map[device.roomID].name
|
||||||
|
@ -4,6 +4,7 @@ from datetime import timedelta
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from meteofrance.client import MeteoFranceClient
|
from meteofrance.client import MeteoFranceClient
|
||||||
|
from meteofrance.helpers import is_valid_warning_department
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||||
@ -131,7 +132,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool
|
|||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Department corresponding to %s is %s", entry.title, department,
|
"Department corresponding to %s is %s", entry.title, department,
|
||||||
)
|
)
|
||||||
if department:
|
if is_valid_warning_department(department):
|
||||||
if not hass.data[DOMAIN].get(department):
|
if not hass.data[DOMAIN].get(department):
|
||||||
coordinator_alert = DataUpdateCoordinator(
|
coordinator_alert = DataUpdateCoordinator(
|
||||||
hass,
|
hass,
|
||||||
@ -155,7 +156,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Weather alert not available: The city %s is not in France or Andorre.",
|
"Weather alert not available: The city %s is not in metropolitan France or Andorre.",
|
||||||
entry.title,
|
entry.title,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -3,6 +3,12 @@
|
|||||||
"name": "Météo-France",
|
"name": "Météo-France",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/meteo_france",
|
"documentation": "https://www.home-assistant.io/integrations/meteo_france",
|
||||||
"requirements": ["meteofrance-api==0.1.0"],
|
"requirements": [
|
||||||
"codeowners": ["@hacf-fr", "@oncleben31", "@Quentame"]
|
"meteofrance-api==0.1.1"
|
||||||
|
],
|
||||||
|
"codeowners": [
|
||||||
|
"@hacf-fr",
|
||||||
|
"@oncleben31",
|
||||||
|
"@Quentame"
|
||||||
|
]
|
||||||
}
|
}
|
@ -262,8 +262,11 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
|
|||||||
for room in home["rooms"]:
|
for room in home["rooms"]:
|
||||||
if data["event_type"] == "set_point":
|
if data["event_type"] == "set_point":
|
||||||
if self._id == room["id"]:
|
if self._id == room["id"]:
|
||||||
if room["therm_setpoint_mode"] == "off":
|
if room["therm_setpoint_mode"] == STATE_NETATMO_OFF:
|
||||||
self._hvac_mode = HVAC_MODE_OFF
|
self._hvac_mode = HVAC_MODE_OFF
|
||||||
|
elif room["therm_setpoint_mode"] == STATE_NETATMO_MAX:
|
||||||
|
self._hvac_mode = HVAC_MODE_HEAT
|
||||||
|
self._target_temperature = DEFAULT_MAX_TEMP
|
||||||
else:
|
else:
|
||||||
self._target_temperature = room["therm_setpoint_temperature"]
|
self._target_temperature = room["therm_setpoint_temperature"]
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
@ -239,6 +239,7 @@ class OnkyoDevice(MediaPlayerEntity):
|
|||||||
self._source_mapping = sources
|
self._source_mapping = sources
|
||||||
self._reverse_mapping = {value: key for key, value in sources.items()}
|
self._reverse_mapping = {value: key for key, value in sources.items()}
|
||||||
self._attributes = {}
|
self._attributes = {}
|
||||||
|
self._hdmi_out_supported = True
|
||||||
|
|
||||||
def command(self, command):
|
def command(self, command):
|
||||||
"""Run an eiscp command and catch connection errors."""
|
"""Run an eiscp command and catch connection errors."""
|
||||||
@ -251,6 +252,7 @@ class OnkyoDevice(MediaPlayerEntity):
|
|||||||
else:
|
else:
|
||||||
_LOGGER.info("%s is disconnected. Attempting to reconnect", self._name)
|
_LOGGER.info("%s is disconnected. Attempting to reconnect", self._name)
|
||||||
return False
|
return False
|
||||||
|
_LOGGER.debug("Result for %s: %s", command, result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
@ -268,7 +270,13 @@ class OnkyoDevice(MediaPlayerEntity):
|
|||||||
volume_raw = self.command("volume query")
|
volume_raw = self.command("volume query")
|
||||||
mute_raw = self.command("audio-muting query")
|
mute_raw = self.command("audio-muting query")
|
||||||
current_source_raw = self.command("input-selector query")
|
current_source_raw = self.command("input-selector query")
|
||||||
|
# If the following command is sent to a device with only one HDMI out,
|
||||||
|
# the display shows 'Not Available'.
|
||||||
|
# We avoid this by checking if HDMI out is supported
|
||||||
|
if self._hdmi_out_supported:
|
||||||
hdmi_out_raw = self.command("hdmi-output-selector query")
|
hdmi_out_raw = self.command("hdmi-output-selector query")
|
||||||
|
else:
|
||||||
|
hdmi_out_raw = []
|
||||||
preset_raw = self.command("preset query")
|
preset_raw = self.command("preset query")
|
||||||
if not (volume_raw and mute_raw and current_source_raw):
|
if not (volume_raw and mute_raw and current_source_raw):
|
||||||
return
|
return
|
||||||
@ -298,6 +306,8 @@ class OnkyoDevice(MediaPlayerEntity):
|
|||||||
if not hdmi_out_raw:
|
if not hdmi_out_raw:
|
||||||
return
|
return
|
||||||
self._attributes["video_out"] = ",".join(hdmi_out_raw[1])
|
self._attributes["video_out"] = ",".join(hdmi_out_raw[1])
|
||||||
|
if hdmi_out_raw[1] == "N/A":
|
||||||
|
self._hdmi_out_supported = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
@ -80,11 +80,10 @@ class ZwaveLight(ZWaveDeviceEntity, LightEntity):
|
|||||||
if self.values.dimming_duration is not None:
|
if self.values.dimming_duration is not None:
|
||||||
self._supported_features |= SUPPORT_TRANSITION
|
self._supported_features |= SUPPORT_TRANSITION
|
||||||
|
|
||||||
if self.values.color is None or self.values.color_channels is None:
|
if self.values.color is not None:
|
||||||
return
|
|
||||||
|
|
||||||
self._supported_features |= SUPPORT_COLOR
|
self._supported_features |= SUPPORT_COLOR
|
||||||
|
|
||||||
|
if self.values.color_channels is not None:
|
||||||
# Support Color Temp if both white channels
|
# Support Color Temp if both white channels
|
||||||
if (self.values.color_channels.value & COLOR_CHANNEL_WARM_WHITE) and (
|
if (self.values.color_channels.value & COLOR_CHANNEL_WARM_WHITE) and (
|
||||||
self.values.color_channels.value & COLOR_CHANNEL_COLD_WHITE
|
self.values.color_channels.value & COLOR_CHANNEL_COLD_WHITE
|
||||||
@ -97,7 +96,8 @@ class ZwaveLight(ZWaveDeviceEntity, LightEntity):
|
|||||||
):
|
):
|
||||||
self._supported_features |= SUPPORT_WHITE_VALUE
|
self._supported_features |= SUPPORT_WHITE_VALUE
|
||||||
|
|
||||||
self._calculate_rgb_values()
|
if self.values.color is not None:
|
||||||
|
self._calculate_color_values()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def brightness(self):
|
def brightness(self):
|
||||||
@ -248,10 +248,8 @@ class ZwaveLight(ZWaveDeviceEntity, LightEntity):
|
|||||||
|
|
||||||
self.values.primary.send_value(0)
|
self.values.primary.send_value(0)
|
||||||
|
|
||||||
def _calculate_rgb_values(self):
|
def _calculate_color_values(self):
|
||||||
# Color Channels
|
"""Parse color rgb and color temperature data."""
|
||||||
self._color_channels = self.values.color_channels.data[ATTR_VALUE]
|
|
||||||
|
|
||||||
# Color Data String
|
# Color Data String
|
||||||
data = self.values.color.data[ATTR_VALUE]
|
data = self.values.color.data[ATTR_VALUE]
|
||||||
|
|
||||||
@ -259,6 +257,12 @@ class ZwaveLight(ZWaveDeviceEntity, LightEntity):
|
|||||||
rgb = [int(data[1:3], 16), int(data[3:5], 16), int(data[5:7], 16)]
|
rgb = [int(data[1:3], 16), int(data[3:5], 16), int(data[5:7], 16)]
|
||||||
self._hs = color_util.color_RGB_to_hs(*rgb)
|
self._hs = color_util.color_RGB_to_hs(*rgb)
|
||||||
|
|
||||||
|
if self.values.color_channels is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Color Channels
|
||||||
|
self._color_channels = self.values.color_channels.data[ATTR_VALUE]
|
||||||
|
|
||||||
# Parse remaining color channels. OpenZWave appends white channels
|
# Parse remaining color channels. OpenZWave appends white channels
|
||||||
# that are present.
|
# that are present.
|
||||||
index = 7
|
index = 7
|
||||||
|
@ -534,6 +534,14 @@ class Recorder(threading.Thread):
|
|||||||
if self.db_url != SQLITE_URL_PREFIX and self.db_url.startswith(
|
if self.db_url != SQLITE_URL_PREFIX and self.db_url.startswith(
|
||||||
SQLITE_URL_PREFIX
|
SQLITE_URL_PREFIX
|
||||||
):
|
):
|
||||||
|
with self.hass.timeout.freeze(DOMAIN):
|
||||||
|
#
|
||||||
|
# Here we run an sqlite3 quick_check. In the majority
|
||||||
|
# of cases, the quick_check takes under 10 seconds.
|
||||||
|
#
|
||||||
|
# On systems with very large databases and
|
||||||
|
# very slow disk or cpus, this can take a while.
|
||||||
|
#
|
||||||
validate_or_move_away_sqlite_database(self.db_url)
|
validate_or_move_away_sqlite_database(self.db_url)
|
||||||
|
|
||||||
if self.engine is not None:
|
if self.engine is not None:
|
||||||
|
@ -250,7 +250,7 @@ class SamsungTVWSBridge(SamsungTVBridge):
|
|||||||
host=self.host,
|
host=self.host,
|
||||||
port=self.port,
|
port=self.port,
|
||||||
token=self.token,
|
token=self.token,
|
||||||
timeout=10,
|
timeout=8,
|
||||||
name=VALUE_CONF_NAME,
|
name=VALUE_CONF_NAME,
|
||||||
)
|
)
|
||||||
self._remote.open()
|
self._remote.open()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Constants used by Home Assistant components."""
|
"""Constants used by Home Assistant components."""
|
||||||
MAJOR_VERSION = 0
|
MAJOR_VERSION = 0
|
||||||
MINOR_VERSION = 114
|
MINOR_VERSION = 114
|
||||||
PATCH_VERSION = "1"
|
PATCH_VERSION = "2"
|
||||||
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||||
__version__ = f"{__short_version__}.{PATCH_VERSION}"
|
__version__ = f"{__short_version__}.{PATCH_VERSION}"
|
||||||
REQUIRED_PYTHON_VER = (3, 7, 1)
|
REQUIRED_PYTHON_VER = (3, 7, 1)
|
||||||
|
@ -902,7 +902,7 @@ messagebird==1.2.0
|
|||||||
meteoalertapi==0.1.6
|
meteoalertapi==0.1.6
|
||||||
|
|
||||||
# homeassistant.components.meteo_france
|
# homeassistant.components.meteo_france
|
||||||
meteofrance-api==0.1.0
|
meteofrance-api==0.1.1
|
||||||
|
|
||||||
# homeassistant.components.mfi
|
# homeassistant.components.mfi
|
||||||
mficlient==0.3.0
|
mficlient==0.3.0
|
||||||
|
@ -424,7 +424,7 @@ mbddns==0.1.2
|
|||||||
mcstatus==2.3.0
|
mcstatus==2.3.0
|
||||||
|
|
||||||
# homeassistant.components.meteo_france
|
# homeassistant.components.meteo_france
|
||||||
meteofrance-api==0.1.0
|
meteofrance-api==0.1.1
|
||||||
|
|
||||||
# homeassistant.components.mfi
|
# homeassistant.components.mfi
|
||||||
mficlient==0.3.0
|
mficlient==0.3.0
|
||||||
|
@ -33,6 +33,12 @@ def light_new_ozw_data_fixture():
|
|||||||
return load_fixture("ozw/light_new_ozw_network_dump.csv")
|
return load_fixture("ozw/light_new_ozw_network_dump.csv")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="light_pure_rgb_dimmer_data", scope="session")
|
||||||
|
def light_pure_rgb_dimmer_data_fixture():
|
||||||
|
"""Load light rgb and dimmer MQTT data and return it."""
|
||||||
|
return load_fixture("ozw/light_pure_rgb_dimmer_dump.csv")
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="light_no_rgb_data", scope="session")
|
@pytest.fixture(name="light_no_rgb_data", scope="session")
|
||||||
def light_no_rgb_data_fixture():
|
def light_no_rgb_data_fixture():
|
||||||
"""Load light dimmer MQTT data and return it."""
|
"""Load light dimmer MQTT data and return it."""
|
||||||
@ -139,6 +145,17 @@ async def light_rgb_msg_fixture(hass):
|
|||||||
return message
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="light_pure_rgb_msg")
|
||||||
|
async def light_pure_rgb_msg_fixture(hass):
|
||||||
|
"""Return a mock MQTT msg with a pure rgb light actuator message."""
|
||||||
|
light_json = json.loads(
|
||||||
|
await hass.async_add_executor_job(load_fixture, "ozw/light_pure_rgb.json")
|
||||||
|
)
|
||||||
|
message = MQTTMessage(topic=light_json["topic"], payload=light_json["payload"])
|
||||||
|
message.encode()
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="switch_msg")
|
@pytest.fixture(name="switch_msg")
|
||||||
async def switch_msg_fixture(hass):
|
async def switch_msg_fixture(hass):
|
||||||
"""Return a mock MQTT msg with a switch actuator message."""
|
"""Return a mock MQTT msg with a switch actuator message."""
|
||||||
|
@ -350,6 +350,48 @@ async def test_light(hass, light_data, light_msg, light_rgb_msg, sent_messages):
|
|||||||
assert state.attributes["color_temp"] == 153
|
assert state.attributes["color_temp"] == 153
|
||||||
|
|
||||||
|
|
||||||
|
async def test_pure_rgb_dimmer_light(
|
||||||
|
hass, light_pure_rgb_dimmer_data, light_msg, light_pure_rgb_msg, sent_messages
|
||||||
|
):
|
||||||
|
"""Test light with no color channels command class."""
|
||||||
|
receive_message = await setup_ozw(hass, fixture=light_pure_rgb_dimmer_data)
|
||||||
|
|
||||||
|
# Test loaded
|
||||||
|
state = hass.states.get("light.kitchen_rgb_strip_level")
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == "on"
|
||||||
|
assert state.attributes["supported_features"] == 17
|
||||||
|
|
||||||
|
# Test setting hs_color
|
||||||
|
new_color = [300, 70]
|
||||||
|
await hass.services.async_call(
|
||||||
|
"light",
|
||||||
|
"turn_on",
|
||||||
|
{"entity_id": "light.kitchen_rgb_strip_level", "hs_color": new_color},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert len(sent_messages) == 2
|
||||||
|
msg = sent_messages[-1]
|
||||||
|
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
|
||||||
|
assert msg["payload"] == {"Value": 255, "ValueIDKey": 122257425}
|
||||||
|
|
||||||
|
msg = sent_messages[-2]
|
||||||
|
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
|
||||||
|
assert msg["payload"] == {"Value": "#ff4cff0000", "ValueIDKey": 122470423}
|
||||||
|
|
||||||
|
# Feedback on state
|
||||||
|
light_pure_rgb_msg.decode()
|
||||||
|
light_pure_rgb_msg.payload["Value"] = "#ff4cff0000"
|
||||||
|
light_pure_rgb_msg.encode()
|
||||||
|
receive_message(light_pure_rgb_msg)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("light.kitchen_rgb_strip_level")
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == "on"
|
||||||
|
assert state.attributes["hs_color"] == (300.0, 70.196)
|
||||||
|
|
||||||
|
|
||||||
async def test_no_rgb_light(hass, light_no_rgb_data, light_no_rgb_msg, sent_messages):
|
async def test_no_rgb_light(hass, light_no_rgb_data, light_no_rgb_msg, sent_messages):
|
||||||
"""Test setting up config entry."""
|
"""Test setting up config entry."""
|
||||||
receive_message = await setup_ozw(hass, fixture=light_no_rgb_data)
|
receive_message = await setup_ozw(hass, fixture=light_no_rgb_data)
|
||||||
|
@ -97,7 +97,7 @@ MOCK_CALLS_ENTRY_WS = {
|
|||||||
"host": "fake",
|
"host": "fake",
|
||||||
"name": "HomeAssistant",
|
"name": "HomeAssistant",
|
||||||
"port": 8001,
|
"port": 8001,
|
||||||
"timeout": 10,
|
"timeout": 8,
|
||||||
"token": "abcde",
|
"token": "abcde",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
25
tests/fixtures/ozw/light_pure_rgb.json
vendored
Normal file
25
tests/fixtures/ozw/light_pure_rgb.json
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"topic": "OpenZWave/1/node/7/instance/1/commandclass/51/value/122470423/",
|
||||||
|
"payload": {
|
||||||
|
"Label": "Color",
|
||||||
|
"Value": "#ff00000000",
|
||||||
|
"Units": "#RRGGBBWW",
|
||||||
|
"ValueSet": false,
|
||||||
|
"ValuePolled": false,
|
||||||
|
"ChangeVerified": false,
|
||||||
|
"Min": 0,
|
||||||
|
"Max": 0,
|
||||||
|
"Type": "String",
|
||||||
|
"Instance": 1,
|
||||||
|
"CommandClass": "COMMAND_CLASS_COLOR",
|
||||||
|
"Index": 0,
|
||||||
|
"Node": 7,
|
||||||
|
"Genre": "User",
|
||||||
|
"Help": "Color (in RGB format)",
|
||||||
|
"ValueIDKey": 122470423,
|
||||||
|
"ReadOnly": false,
|
||||||
|
"WriteOnly": false,
|
||||||
|
"Event": "valueAdded",
|
||||||
|
"TimeStamp": 1597142799
|
||||||
|
}
|
||||||
|
}
|
131
tests/fixtures/ozw/light_pure_rgb_dimmer_dump.csv
vendored
Normal file
131
tests/fixtures/ozw/light_pure_rgb_dimmer_dump.csv
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user