Skip to content

Commit

Permalink
Merge branch 'dev' into rc
Browse files Browse the repository at this point in the history
  • Loading branch information
puddly committed Apr 10, 2022
2 parents 13fe63e + 3857bfe commit a2952c8
Show file tree
Hide file tree
Showing 11 changed files with 149 additions and 16 deletions.
26 changes: 23 additions & 3 deletions tests/test_ota_image.py
Expand Up @@ -314,6 +314,11 @@ def test_get_image_block_offset_too_large(raw_header, raw_sub_element):
img.get_image_block(offset, size)


def test_cached_image_wrapping(image):
cached_img = CachedImage(image)
assert cached_img.header is image.header


def wrap_ikea(data):
header = bytearray(100)
header[0:4] = b"NGIS"
Expand Down Expand Up @@ -400,6 +405,21 @@ def test_parse_ota_hue_invalid():
firmware.parse_ota_image(header.replace(manufacturer_id=12).serialize() + rest)


def test_cached_image_wrapping(image):
cached_img = CachedImage(image)
assert cached_img.header is image.header
def test_legrand_container_unwrapping(image):
# Unwrapped size prefix and 1 + 16 byte suffix
data = (
t.uint32_t(len(image.serialize())).serialize()
+ image.serialize()
+ b"\x01"
+ b"abcdabcdabcdabcd"
)

with pytest.raises(ValueError):
firmware.parse_ota_image(data[:-1])

with pytest.raises(ValueError):
firmware.parse_ota_image(b"\xFF" + data[1:])

img, rest = firmware.parse_ota_image(data)
assert not rest
assert img == image
12 changes: 12 additions & 0 deletions tests/test_struct.py
Expand Up @@ -774,3 +774,15 @@ class TestStruct(t.Struct):
s1 = TestStruct(foo=1, bar=2, baz="asd")

assert repr(s1) == "TestStruct(foo=2, bar=bar, baz=baz)"


def test_skip_missing():
class TestStruct(t.Struct):
foo: t.uint8_t
bar: t.uint16_t

assert TestStruct(foo=1).as_dict() == {"foo": 1, "bar": None}
assert TestStruct(foo=1).as_dict(skip_missing=True) == {"foo": 1}

assert TestStruct(foo=1).as_tuple() == (1, None)
assert TestStruct(foo=1).as_tuple(skip_missing=True) == (1,)
4 changes: 2 additions & 2 deletions zigpy/__init__.py
@@ -1,5 +1,5 @@
MAJOR_VERSION = 0
MINOR_VERSION = 44
PATCH_VERSION = "1"
MINOR_VERSION = 45
PATCH_VERSION = "0.dev0"
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__ = f"{__short_version__}.{PATCH_VERSION}"
87 changes: 87 additions & 0 deletions zigpy/ota/OTA_URLs.md
@@ -0,0 +1,87 @@
# Zigbee OTA source provider sources for these and others

Collection of external Zigbee OTA firmware images from official and unofficial OTA provider sources.

### Koenkk zigbee-OTA repository

Koenkk zigbee-OTA repository host third-party OTA firmware images and external URLs for many third-party Zigbee OTA firmware images.

https://github.com/Koenkk/zigbee-OTA/tree/master/images

https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/index.json

### Dresden Elektronik

Dresden Elektronik Zigbee OTA firmware images are made publicly available by Dresden Elektronik (first-party) at the following URL:

https://github.com/dresden-elektronik/deconz-rest-plugin/wiki/OTA-Image-Types---Firmware-versions

Dresden Elektronik also provide third-party OTA firmware images and external URLs for many third-party Zigbee OTA firmware images.

### EUROTRONICS

EUROTRONICS Zigbee OTA firmware images are made publicly available by EUROTRONIC Technology (first-party) at the following URL:

https://github.com/EUROTRONIC-Technology/Spirit-ZigBee/releases/download/

### IKEA Trådfri

IKEA Tradfi Zigbee OTA firmware images are made publicly available by IKEA (first-party) at the following URL:

Download-URL:

http://fw.ota.homesmart.ikea.net/feed/version_info.json

Download-URL (Test/Beta-Version):

http://fw.test.ota.homesmart.ikea.net/feed/version_info.json

Release changelogs

https://ww8.ikea.com/ikeahomesmart/releasenotes/releasenotes.html

### LEDVANCE/Sylvania and OSRAM Lightify

LEDVANCE/Sylvania and OSRAM Lightify Zigbee OTA firmware images are made publicly available by LEDVANCE (first-party) at the following URL:

https://update.ledvance.com/firmware-overview

https://api.update.ledvance.com/v1/zigbee/firmwares/download

https://consumer.sylvania.com/our-products/smart/sylvania-smart-zigbee-products-menu/index.jsp

### Legrand/Netatmo

Legrand/Netatmo Zigbee OTA firmware images are made publicly available by Legrand (first-party) at the following URL:

https://developer.legrand.com/documentation/operating-manual/ https://developer.legrand.com/documentation/firmwares-download/

### LiXee

LiXee Zigbee OTA firmware images are made publicly available by Fairecasoimeme / ZiGate (first-party) at the following URL:

https://github.com/fairecasoimeme/Zlinky_TIC/releases

### SALUS/Computime

SALUS/Computime Hue Zigbee OTA firmware images are made publicly available by SALUS (first-party) at the following URL:

https://eu.salusconnect.io/demo/default/status/firmware

### Sengled

Sengled Zigbee OTA firmware images are made publicly available by Dresden Elektronik (third-party) at the following URL:

https://github.com/dresden-elektronik/deconz-rest-plugin/wiki/OTA-Image-Types---Firmware-versions#sengled

### Philips Hue (Signify)

Philips Hue (Signify) Zigbee OTA firmware images are made publicly available by Dresden Elektronik (third-party) at the following URL:

https://github.com/dresden-elektronik/deconz-rest-plugin/wiki/OTA-Image-Types---Firmware-versions#philips-hue

### Ubisys

Ubisys Zigbee OTA firmware images are made publicly available by Ubisys (first-party) at the following URL:

https://www.ubisys.de/en/support/firmware/
8 changes: 6 additions & 2 deletions zigpy/ota/image.py
Expand Up @@ -223,8 +223,12 @@ def parse_ota_image(data: bytes) -> tuple[BaseOTAImage, bytes]:
Attempts to extract any known OTA image type from data. Does not validate firmware.
"""

# IKEA container needs to be unwrapped
if data.startswith(b"NGIS"):
if len(data) > 4 and int.from_bytes(data[0:4], "little") + 21 == len(data):
# Legrand OTA images are prefixed with their unwrapped size and include a 1 + 16
# byte suffix
return OTAImage.deserialize(data[4:-17])
elif data.startswith(b"NGIS"):
# IKEA container needs to be unwrapped
if len(data) <= 24:
raise ValueError(
f"Data too short to contain IKEA container header: {len(data)}"
Expand Down
18 changes: 14 additions & 4 deletions zigpy/types/struct.py
Expand Up @@ -184,11 +184,21 @@ def assigned_fields(self, *, strict=False) -> list[tuple[StructField, typing.Any

return assigned_fields

def as_dict(self) -> dict[str, typing.Any]:
return {f.name: getattr(self, f.name) for f in self.fields}
def as_dict(self, *, skip_missing: bool = False) -> dict[str, typing.Any]:
d = {}

def as_tuple(self) -> tuple:
return tuple(getattr(self, f.name) for f in self.fields)
for f in self.fields:
value = getattr(self, f.name)

if value is None and skip_missing:
continue

d[f.name] = value

return d

def as_tuple(self, *, skip_missing: bool = False) -> tuple:
return tuple(self.as_dict(skip_missing=skip_missing).values())

def serialize(self) -> bytes:
chunks = []
Expand Down
2 changes: 1 addition & 1 deletion zigpy/zcl/__init__.py
Expand Up @@ -207,7 +207,7 @@ def from_id(
cluster.cluster_id = cluster_id
return cluster

LOGGER.warning("Unknown cluster 0x%04X", cluster_id)
LOGGER.debug("Unknown cluster 0x%04X", cluster_id)

cluster = cls(endpoint, is_server)
cluster.cluster_id = cluster_id
Expand Down
2 changes: 1 addition & 1 deletion zigpy/zcl/clusters/closures.py
Expand Up @@ -336,7 +336,7 @@ class EventType(t.enum8):
"set_holiday_schedule",
{
"holiday_schedule_id": t.uint8_t,
"loca_start_time": t.LocalTime,
"local_start_time": t.LocalTime,
"local_end_time": t.LocalTime,
"operating_mode_during_holiday": OperatingMode,
},
Expand Down
2 changes: 1 addition & 1 deletion zigpy/zcl/clusters/general.py
Expand Up @@ -1380,7 +1380,7 @@ class ImageNotifyPayloadType(t.enum8):
"file_offset": t.uint32_t,
"maximum_data_size": t.uint8_t,
"request_node_addr?": t.EUI64,
"minumum_block_period?": t.uint16_t,
"minimum_block_period?": t.uint16_t,
},
False,
),
Expand Down
2 changes: 1 addition & 1 deletion zigpy/zcl/clusters/homeautomation.py
Expand Up @@ -58,7 +58,7 @@ class ApplianceEventAlerts(Cluster):
0x00: ZCLCommandDef("get_alerts", {}, False)
}
client_commands: dict[int, ZCLCommandDef] = {
0x00: ZCLCommandDef("get_alarts_response", {}, True),
0x00: ZCLCommandDef("get_alerts_response", {}, True),
0x01: ZCLCommandDef("alerts_notification", {}, False),
0x02: ZCLCommandDef("event_notification", {}, False),
}
Expand Down
2 changes: 1 addition & 1 deletion zigpy/zcl/clusters/lighting.py
Expand Up @@ -148,7 +148,7 @@ class ColorLoopDirection(t.enum8):
0x02: ZCLCommandDef(
"step_hue",
{
"setp_mode": StepMode,
"step_mode": StepMode,
"step_size": t.uint8_t,
"transition_time": t.uint8_t,
"options_mask?": t.bitmap8,
Expand Down

0 comments on commit a2952c8

Please sign in to comment.