rf-protocols 4.0.1__tar.gz → 4.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/PKG-INFO +1 -1
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/pyproject.toml +1 -1
- rf_protocols-4.2.0/rf_protocols/codes/harbor_breeze/a25/__init__.py +34 -0
- rf_protocols-4.2.0/rf_protocols/commands/harbor_breeze_a25.py +71 -0
- rf_protocols-4.2.0/rf_protocols/commands/marantec.py +76 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols.egg-info/PKG-INFO +1 -1
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols.egg-info/SOURCES.txt +3 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/LICENSE +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/README.md +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/__init__.py +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/codes/honeywell/string_lights/__init__.py +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/codes/honeywell/string_lights/turn_off.sub +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/codes/honeywell/string_lights/turn_on.sub +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/codes/novy/cooker_hood/__init__.py +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/codes/somfy/rts/__init__.py +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/commands/__init__.py +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/commands/ev1527.py +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/commands/kaku.py +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/commands/novy.py +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/commands/ook.py +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/commands/pilota_casa.py +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/commands/pt2262.py +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/commands/somfy_rts.py +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/loader.py +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/parser.py +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols.egg-info/dependency_links.txt +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols.egg-info/requires.txt +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols.egg-info/top_level.txt +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/setup.cfg +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/tests/test_loader.py +0 -0
- {rf_protocols-4.0.1 → rf_protocols-4.2.0}/tests/test_parser.py +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Harbor Breeze A25 command identifiers."""
|
|
2
|
+
|
|
3
|
+
from enum import IntEnum
|
|
4
|
+
|
|
5
|
+
from ....commands.harbor_breeze_a25 import HarborBreezeA25Command
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class HarborBreezeA25Button(IntEnum):
|
|
9
|
+
"""Known Harbor Breeze A25 button codes.
|
|
10
|
+
|
|
11
|
+
Values are the decoded 6-bit command field found in the normalized frame.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
BLOW = 0b111010
|
|
15
|
+
BREEZE = 0b000110
|
|
16
|
+
FAN_1 = 0b011110
|
|
17
|
+
FAN_2 = 0b101110
|
|
18
|
+
FAN_3 = 0b001110
|
|
19
|
+
FAN_4 = 0b110110
|
|
20
|
+
FAN_5 = 0b010110
|
|
21
|
+
FAN_6 = 0b100110
|
|
22
|
+
HOME = 0b000011
|
|
23
|
+
LIGHT = 0b011010
|
|
24
|
+
POWER = 0b111110
|
|
25
|
+
SUCK = 0b111000
|
|
26
|
+
TIMER = 0b001000
|
|
27
|
+
TIMER_2H = 0b011011
|
|
28
|
+
TIMER_4H = 0b101011
|
|
29
|
+
TIMER_8H = 0b001011
|
|
30
|
+
|
|
31
|
+
def to_command(self, *, address: int) -> HarborBreezeA25Command:
|
|
32
|
+
"""Build a Harbor Breeze command for this button and address."""
|
|
33
|
+
return HarborBreezeA25Command(address=address, command=self.value)
|
|
34
|
+
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Harbor Breeze A25 RF command encoder."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import override
|
|
6
|
+
|
|
7
|
+
from . import ModulationType, RadioFrequencyCommand
|
|
8
|
+
|
|
9
|
+
_DEFAULT_FREQUENCY = 315_000_000
|
|
10
|
+
_DEFAULT_FRAME_COUNT = 6
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class HarborBreezeA25Command(RadioFrequencyCommand):
|
|
14
|
+
"""Encode Harbor Breeze A25 transmissions.
|
|
15
|
+
|
|
16
|
+
The frame layout consists of a three-symbol preamble, a 13-bit address,
|
|
17
|
+
two fixed bits, a 6-bit command field, two fixed trailer bits, and a final
|
|
18
|
+
inter-frame gap. The complete frame is emitted six times per transmission.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
address: int
|
|
22
|
+
command: int
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
*,
|
|
27
|
+
address: int,
|
|
28
|
+
command: int,
|
|
29
|
+
frequency: int = _DEFAULT_FREQUENCY,
|
|
30
|
+
) -> None:
|
|
31
|
+
"""Initialize the Harbor Breeze command.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
address: 13-bit receiver address (0..8191).
|
|
35
|
+
command: 6-bit command value (0..63).
|
|
36
|
+
frequency: RF frequency in Hz.
|
|
37
|
+
"""
|
|
38
|
+
if address < 0 or address >= (1 << 13):
|
|
39
|
+
raise ValueError("address must be in range 0..8191 (13-bit)")
|
|
40
|
+
if command < 0 or command >= (1 << 6):
|
|
41
|
+
raise ValueError("command must be in range 0..63 (6-bit)")
|
|
42
|
+
|
|
43
|
+
super().__init__(
|
|
44
|
+
frequency=frequency,
|
|
45
|
+
modulation=ModulationType.OOK,
|
|
46
|
+
repeat_count=0,
|
|
47
|
+
)
|
|
48
|
+
self.address = address
|
|
49
|
+
self.command = command
|
|
50
|
+
|
|
51
|
+
@override
|
|
52
|
+
def get_raw_timings(self) -> list[int]:
|
|
53
|
+
"""Compute the repeated Harbor Breeze transmission timings."""
|
|
54
|
+
short_us = 493
|
|
55
|
+
long_us = 952
|
|
56
|
+
frame_gap_us = 10_936
|
|
57
|
+
|
|
58
|
+
payload_bits = f"{self.address:013b}00{self.command:06b}10"
|
|
59
|
+
|
|
60
|
+
frame: list[int] = [short_us, -long_us, short_us]
|
|
61
|
+
for bit in payload_bits:
|
|
62
|
+
if bit == "0":
|
|
63
|
+
frame.extend([-long_us, short_us])
|
|
64
|
+
else:
|
|
65
|
+
frame.extend([-short_us, long_us])
|
|
66
|
+
frame.append(-frame_gap_us)
|
|
67
|
+
|
|
68
|
+
timings: list[int] = []
|
|
69
|
+
for _ in range(_DEFAULT_FRAME_COUNT):
|
|
70
|
+
timings.extend(frame)
|
|
71
|
+
return timings
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Encoder for Marantec garage door / gate RF remotes.
|
|
2
|
+
|
|
3
|
+
868.35 MHz OOK (433.92 MHz variant available), Manchester-coded. Encodes a
|
|
4
|
+
static, indefinitely valid (non-rolling) 49-bit code. Does not cover
|
|
5
|
+
rolling-code Marantec systems or the unrelated 24-bit "Marantec24" cloner
|
|
6
|
+
protocol.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import override
|
|
12
|
+
|
|
13
|
+
from . import ModulationType, RadioFrequencyCommand
|
|
14
|
+
|
|
15
|
+
_MARANTEC_FREQUENCY = 868_350_000
|
|
16
|
+
_MARANTEC_REPEAT_COUNT = 4
|
|
17
|
+
|
|
18
|
+
_TE_SHORT = 1000
|
|
19
|
+
_TE_LONG = 2000
|
|
20
|
+
_HEADER_LOW = _TE_LONG * 5
|
|
21
|
+
|
|
22
|
+
_BIT_COUNT = 49
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class MarantecCommand(RadioFrequencyCommand):
|
|
26
|
+
"""Encode a Marantec static-code garage door / gate frame."""
|
|
27
|
+
|
|
28
|
+
code: int
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
*,
|
|
33
|
+
code: int,
|
|
34
|
+
frequency: int = _MARANTEC_FREQUENCY,
|
|
35
|
+
) -> None:
|
|
36
|
+
"""Initialize the Marantec command."""
|
|
37
|
+
if code < 0 or code >= (1 << _BIT_COUNT):
|
|
38
|
+
raise ValueError("code must be a 49-bit value (0..2**49-1)")
|
|
39
|
+
super().__init__(
|
|
40
|
+
frequency=frequency,
|
|
41
|
+
modulation=ModulationType.OOK,
|
|
42
|
+
repeat_count=_MARANTEC_REPEAT_COUNT,
|
|
43
|
+
)
|
|
44
|
+
self.code = code
|
|
45
|
+
|
|
46
|
+
@override
|
|
47
|
+
def get_raw_timings(self) -> list[int]:
|
|
48
|
+
"""Compute the frame timings as signed mark/space microseconds.
|
|
49
|
+
|
|
50
|
+
Manchester (bit 0 = mark then space, bit 1 = space then mark), 49 bits,
|
|
51
|
+
trailing inter-frame gap. Frame starts on a mark so polarity (assigned
|
|
52
|
+
by index parity) stays correct; the first bit's leading space and the
|
|
53
|
+
gap are reconstructed across the repeated transmissions.
|
|
54
|
+
"""
|
|
55
|
+
timings: list[int] = []
|
|
56
|
+
|
|
57
|
+
def add(us: int) -> None:
|
|
58
|
+
if timings and (us > 0) == (timings[-1] > 0):
|
|
59
|
+
timings[-1] += us
|
|
60
|
+
else:
|
|
61
|
+
timings.append(us)
|
|
62
|
+
|
|
63
|
+
for idx in range(_BIT_COUNT):
|
|
64
|
+
bit = (self.code >> (_BIT_COUNT - 1 - idx)) & 1
|
|
65
|
+
if idx == 0 and bit:
|
|
66
|
+
add(_TE_SHORT)
|
|
67
|
+
continue
|
|
68
|
+
if bit:
|
|
69
|
+
add(-_TE_SHORT)
|
|
70
|
+
add(_TE_SHORT)
|
|
71
|
+
else:
|
|
72
|
+
add(_TE_SHORT)
|
|
73
|
+
add(-_TE_SHORT)
|
|
74
|
+
|
|
75
|
+
add(-_HEADER_LOW)
|
|
76
|
+
return timings
|
|
@@ -9,6 +9,7 @@ rf_protocols.egg-info/SOURCES.txt
|
|
|
9
9
|
rf_protocols.egg-info/dependency_links.txt
|
|
10
10
|
rf_protocols.egg-info/requires.txt
|
|
11
11
|
rf_protocols.egg-info/top_level.txt
|
|
12
|
+
rf_protocols/codes/harbor_breeze/a25/__init__.py
|
|
12
13
|
rf_protocols/codes/honeywell/string_lights/__init__.py
|
|
13
14
|
rf_protocols/codes/honeywell/string_lights/turn_off.sub
|
|
14
15
|
rf_protocols/codes/honeywell/string_lights/turn_on.sub
|
|
@@ -16,7 +17,9 @@ rf_protocols/codes/novy/cooker_hood/__init__.py
|
|
|
16
17
|
rf_protocols/codes/somfy/rts/__init__.py
|
|
17
18
|
rf_protocols/commands/__init__.py
|
|
18
19
|
rf_protocols/commands/ev1527.py
|
|
20
|
+
rf_protocols/commands/harbor_breeze_a25.py
|
|
19
21
|
rf_protocols/commands/kaku.py
|
|
22
|
+
rf_protocols/commands/marantec.py
|
|
20
23
|
rf_protocols/commands/novy.py
|
|
21
24
|
rf_protocols/commands/ook.py
|
|
22
25
|
rf_protocols/commands/pilota_casa.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/codes/honeywell/string_lights/__init__.py
RENAMED
|
File without changes
|
{rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/codes/honeywell/string_lights/turn_off.sub
RENAMED
|
File without changes
|
{rf_protocols-4.0.1 → rf_protocols-4.2.0}/rf_protocols/codes/honeywell/string_lights/turn_on.sub
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|