rf-protocols 3.0.0__tar.gz → 3.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.
Files changed (76) hide show
  1. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/PKG-INFO +1 -1
  2. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/pyproject.toml +1 -1
  3. rf_protocols-3.2.0/rf_protocols/commands/ev1527.py +124 -0
  4. rf_protocols-3.2.0/rf_protocols/commands/kaku.py +153 -0
  5. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols.egg-info/PKG-INFO +1 -1
  6. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols.egg-info/SOURCES.txt +2 -0
  7. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/LICENSE +0 -0
  8. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/README.md +0 -0
  9. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/__init__.py +0 -0
  10. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/honeywell/string_lights/__init__.py +0 -0
  11. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/honeywell/string_lights/turn_off.sub +0 -0
  12. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/honeywell/string_lights/turn_on.sub +0 -0
  13. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/__init__.py +0 -0
  14. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_1/ambient_light.sub +0 -0
  15. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_1/light.sub +0 -0
  16. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_1/minus.sub +0 -0
  17. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_1/plus.sub +0 -0
  18. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_1/power.sub +0 -0
  19. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_10/ambient_light.sub +0 -0
  20. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_10/light.sub +0 -0
  21. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_10/minus.sub +0 -0
  22. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_10/plus.sub +0 -0
  23. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_10/power.sub +0 -0
  24. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_2/ambient_light.sub +0 -0
  25. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_2/light.sub +0 -0
  26. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_2/minus.sub +0 -0
  27. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_2/plus.sub +0 -0
  28. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_2/power.sub +0 -0
  29. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_3/ambient_light.sub +0 -0
  30. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_3/light.sub +0 -0
  31. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_3/minus.sub +0 -0
  32. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_3/plus.sub +0 -0
  33. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_3/power.sub +0 -0
  34. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_4/ambient_light.sub +0 -0
  35. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_4/light.sub +0 -0
  36. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_4/minus.sub +0 -0
  37. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_4/plus.sub +0 -0
  38. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_4/power.sub +0 -0
  39. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_5/ambient_light.sub +0 -0
  40. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_5/light.sub +0 -0
  41. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_5/minus.sub +0 -0
  42. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_5/plus.sub +0 -0
  43. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_5/power.sub +0 -0
  44. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_6/ambient_light.sub +0 -0
  45. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_6/light.sub +0 -0
  46. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_6/minus.sub +0 -0
  47. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_6/plus.sub +0 -0
  48. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_6/power.sub +0 -0
  49. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_7/ambient_light.sub +0 -0
  50. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_7/light.sub +0 -0
  51. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_7/minus.sub +0 -0
  52. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_7/plus.sub +0 -0
  53. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_7/power.sub +0 -0
  54. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_8/ambient_light.sub +0 -0
  55. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_8/light.sub +0 -0
  56. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_8/minus.sub +0 -0
  57. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_8/plus.sub +0 -0
  58. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_8/power.sub +0 -0
  59. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_9/ambient_light.sub +0 -0
  60. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_9/light.sub +0 -0
  61. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_9/minus.sub +0 -0
  62. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_9/plus.sub +0 -0
  63. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/novy/cooker_hood/code_9/power.sub +0 -0
  64. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/codes/somfy/rts/__init__.py +0 -0
  65. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/commands/__init__.py +0 -0
  66. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/commands/ook.py +0 -0
  67. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/commands/pt2262.py +0 -0
  68. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/commands/somfy_rts.py +0 -0
  69. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/loader.py +0 -0
  70. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols/parser.py +0 -0
  71. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols.egg-info/dependency_links.txt +0 -0
  72. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols.egg-info/requires.txt +0 -0
  73. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/rf_protocols.egg-info/top_level.txt +0 -0
  74. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/setup.cfg +0 -0
  75. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/tests/test_loader.py +0 -0
  76. {rf_protocols-3.0.0 → rf_protocols-3.2.0}/tests/test_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rf-protocols
3
- Version: 3.0.0
3
+ Version: 3.2.0
4
4
  Summary: Library to decode and encode radio frequency signals.
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/home-assistant-libs/rf-protocols
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rf-protocols"
7
- version = "3.0.0"
7
+ version = "3.2.0"
8
8
  license = "MIT"
9
9
  description = "Library to decode and encode radio frequency signals."
10
10
  readme = "README.md"
@@ -0,0 +1,124 @@
1
+ """Protocol for EV1527 compatible devices
2
+
3
+ EV1527, RT1527, FP1527 is a simple 24-bit RF protocol used by self-learning remote controls
4
+ and RF switches. It uses Pulse Width Modulation (PWM) encoding where a wide
5
+ pulse represents 1 and a short pulse represents 0.
6
+ The chip has a fixed 20-bit device id and 4 data pin inputs, which are typically used to encode a button or channel number.
7
+ The protocol uses a configurable time base (step duration). Common manufacturers
8
+ and their step durations:
9
+ - Logilight radio controlled sockets EC0001-EC0004: ~300 µs
10
+ - eMylo switches: ~350 µs
11
+
12
+ Encoding:
13
+ Each bit is encoded as follows:
14
+
15
+ ____
16
+ Bit 0 : _| |____________
17
+ |<1a>|<---3a---->|
18
+
19
+ ____________
20
+ Bit 1 : _| |____
21
+ |<----3a---->|<1a>|
22
+
23
+ ____
24
+ Sync : _| |___________ _ _ _ ____________
25
+ |<1a>|<-----------31a------------->|
26
+
27
+ Telegram layout:
28
+ - Sync
29
+ - 24 data bits
30
+ - End of transmission
31
+
32
+ Common data layout:
33
+ - 20 bits: device/unit code
34
+ - 4 bits: button/channel
35
+
36
+ Reference:
37
+ https://www.seegel-systeme.de/2015/09/05/funksteckdosen-mit-dem-raspberry-pi-steuern/
38
+ http://www.sc-tech.cn/en/EV1527.pdf
39
+ """
40
+
41
+ from __future__ import annotations
42
+
43
+ from typing import override
44
+
45
+ from . import ModulationType, RadioFrequencyCommand
46
+
47
+ _DEFAULT_FREQUENCY = 433_920_000
48
+ _DEFAULT_REPEATS = 4
49
+ _DEFAULT_TIMEBASE_US = 275
50
+
51
+
52
+ class EV1527Command(RadioFrequencyCommand):
53
+ """Encode an EV1527-compatible RF command.
54
+
55
+ Data layout:
56
+ - 20 bits: device ID
57
+ - 4 bits: data/button (0..15)
58
+ """
59
+
60
+ device_id: int
61
+ data: int
62
+ timebase_us: int
63
+
64
+ def __init__(
65
+ self,
66
+ *,
67
+ device_id: int,
68
+ data: int,
69
+ frame_repeats: int = _DEFAULT_REPEATS,
70
+ frequency: int = _DEFAULT_FREQUENCY,
71
+ timebase_us: int = _DEFAULT_TIMEBASE_US,
72
+ ) -> None:
73
+ """Initialize the EV1527 command.
74
+
75
+ Args:
76
+ device_id: 20-bit device ID (0..1048575)
77
+ data: Data/button bits (0..15)
78
+ frame_repeats: Number of times to repeat the frame
79
+ frequency: RF frequency in Hz
80
+ timebase_us: Time base in microseconds
81
+ """
82
+
83
+ if device_id < 0 or device_id >= (1 << 20):
84
+ raise ValueError("device_id must be in range 0..1048575 (20-bit)")
85
+ if data < 0 or data > 15:
86
+ raise ValueError("data must be in range 0..15")
87
+
88
+ super().__init__(
89
+ frequency=frequency,
90
+ modulation=ModulationType.OOK,
91
+ repeat_count=frame_repeats,
92
+ )
93
+ self.device_id = device_id
94
+ self.data = data
95
+ self.timebase_us = timebase_us
96
+
97
+ @override
98
+ def get_raw_timings(self) -> list[int]:
99
+ """Compute EV1527 frame timings using PWM encoding.
100
+
101
+ Encodes: sync + 24 data bits (LSB first).
102
+ """
103
+ # PWM symbol definitions (1a = short, 3a = long)
104
+ _symbols = {
105
+ "0": [self.timebase_us, -3 * self.timebase_us],
106
+ "1": [3 * self.timebase_us, -self.timebase_us],
107
+ "sync": [self.timebase_us, -31 * self.timebase_us],
108
+ }
109
+
110
+ # Encode 20-bit device ID in LSB (reverse bits)
111
+ device_id_bits = format(self.device_id, "020b")[::-1]
112
+ symstr: list[str] = [*device_id_bits]
113
+
114
+ # Encode 4-bit data in LSB (reverse bits)
115
+ data_bits = format(self.data, "04b")[::-1]
116
+ symstr.extend(data_bits)
117
+
118
+ # Build timings: sync + symbols
119
+ timings: list[int] = []
120
+ timings.extend(_symbols["sync"])
121
+ for s in symstr:
122
+ timings.extend(_symbols[s])
123
+
124
+ return timings
@@ -0,0 +1,153 @@
1
+ """Protocol for KAKU compatible devices.
2
+
3
+ Pulse Position Modulation with 32 or 36 symbols, used by self-learning
4
+ Intertechno-type sockets and compatible devices (for example some Hama models).
5
+
6
+ Symbols use a time base ``T``:
7
+
8
+ ____ ____
9
+ Bit 0 : _| |____| |____________________
10
+ |<1T>|<1T>|<1T>|<--------5T-------->|
11
+
12
+ ____ ____
13
+ Bit 1 : _| |____________________| |____
14
+ |<1T>|<--------5T-------->|<1T>|<1T>|
15
+
16
+ ____ ____
17
+ Bit X : _| |____| |____
18
+ |<1T>|<1T>|<1T>|<1T>|
19
+
20
+ ____
21
+ Sync : _| |_________ _ _ _ ________
22
+ |<1T>|<----------11T--------->|
23
+
24
+ ____
25
+ Pause : _| |___________ _ _ _ ____________
26
+ |<1T>|<-----------39T-------------->|
27
+
28
+ Telegram layout:
29
+ - Sync
30
+ - 32 or 36 symbols
31
+ - Pause
32
+
33
+ Each transmission is typically repeated four times.
34
+
35
+ Common bit assignment for KAKU-style devices:
36
+ - 26 bits system code
37
+ - 1 bit group (0=single, 1=group)
38
+ - 1 bit on/off
39
+ - 4 bits channel
40
+
41
+ Dimming commands:
42
+ - 26 bits system code
43
+ - 1 bit group (0=single, 1=group)
44
+ - 1 bit X
45
+ - 4 bits channel
46
+ - 4 bits dim level (0-15)
47
+
48
+ Manufacturer-specific notes from the reference:
49
+ - Intertechno (self-learning): step duration around 275 us
50
+ - Hama 00121938: similar format, step duration around 250 us, inverted channel bits
51
+
52
+ Reference chapter:
53
+ https://www.seegel-systeme.de/2015/09/05/funksteckdosen-mit-dem-raspberry-pi-steuern/
54
+ """
55
+
56
+ from __future__ import annotations
57
+
58
+ from typing import override
59
+
60
+ from . import ModulationType, RadioFrequencyCommand
61
+
62
+ _DEFAULT_FREQUENCY = 433_920_000
63
+ _DEFAULT_REPEATS = 4
64
+ _DEFAULT_TIMEBASE_US = 275
65
+
66
+
67
+ class KakuCommand(RadioFrequencyCommand):
68
+ """Encode a KAKU-compatible PPM frame.
69
+
70
+ Data layout is either:
71
+ - 32 symbols: 26-bit id, group bit, on/off bit, 4-bit channel
72
+ - 36 symbols: 26-bit id, group bit, X symbol, 4-bit channel, 4-bit dim level
73
+ """
74
+
75
+ id: int
76
+ group: bool
77
+ channel: int
78
+ on: bool | None
79
+ dimlevel: int | None
80
+ timebase_us: int
81
+
82
+ def __init__(
83
+ self,
84
+ *,
85
+ id: int,
86
+ group: bool,
87
+ channel: int | None = None,
88
+ on: bool | None = None,
89
+ dimlevel: int | None = None,
90
+ frame_repeats: int = _DEFAULT_REPEATS,
91
+ frequency: int = _DEFAULT_FREQUENCY,
92
+ timebase_us: int = _DEFAULT_TIMEBASE_US,
93
+ ) -> None:
94
+ """Initialize the KAKU command."""
95
+
96
+ if id < 0 or id >= (1 << 26):
97
+ raise ValueError("id must be in range 0..67108863 (26-bit)")
98
+ if channel is None:
99
+ if not group:
100
+ raise ValueError("channel is required when group is False")
101
+ channel = 1
102
+ if channel < 1 or channel > 16:
103
+ raise ValueError("channel must be in range 1..16")
104
+ if (on is None) == (dimlevel is None):
105
+ raise ValueError("provide exactly one of 'on' or 'dimlevel'")
106
+ if dimlevel is not None and (dimlevel < 0 or dimlevel > 100):
107
+ raise ValueError("dimlevel must be in range 0..100")
108
+
109
+ super().__init__(
110
+ frequency=frequency,
111
+ modulation=ModulationType.OOK,
112
+ repeat_count=frame_repeats,
113
+ )
114
+ self.id = id
115
+ self.group = group
116
+ self.channel = channel
117
+ self.on = on
118
+ self.dimlevel = dimlevel
119
+ self.timebase_us = timebase_us
120
+
121
+ @override
122
+ def get_raw_timings(self) -> list[int]:
123
+ """Compute KAKU PPM frame timings."""
124
+ _symbols = {
125
+ "0": [self.timebase_us, -self.timebase_us, self.timebase_us, -5 * self.timebase_us],
126
+ "1": [self.timebase_us, -5 * self.timebase_us, self.timebase_us, -self.timebase_us],
127
+ "X": [self.timebase_us, -self.timebase_us, self.timebase_us, -self.timebase_us],
128
+ "sync": [self.timebase_us, -11 * self.timebase_us],
129
+ "pause": [self.timebase_us, -39 * self.timebase_us],
130
+ }
131
+
132
+ # add ID and group bit
133
+ symstr: list[str] = [*format(self.id, "026b"), "1" if self.group else "0"]
134
+
135
+ if self.dimlevel is None:
136
+ # add on/off bit
137
+ symstr.append("1" if self.on else "0")
138
+ else:
139
+ # add X symbol
140
+ symstr.append("X")
141
+
142
+ symstr.extend(format(self.channel - 1, "04b"))
143
+ if self.dimlevel is not None:
144
+ dim_steps = round(self.dimlevel * 15 / 100)
145
+ symstr.extend(format(dim_steps, "04b"))
146
+
147
+ timings: list[int] = []
148
+ timings.extend(_symbols["sync"])
149
+ for s in symstr:
150
+ timings.extend(_symbols[s])
151
+ timings.extend(_symbols["pause"])
152
+
153
+ return timings
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rf-protocols
3
- Version: 3.0.0
3
+ Version: 3.2.0
4
4
  Summary: Library to decode and encode radio frequency signals.
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/home-assistant-libs/rf-protocols
@@ -65,6 +65,8 @@ rf_protocols/codes/novy/cooker_hood/code_9/plus.sub
65
65
  rf_protocols/codes/novy/cooker_hood/code_9/power.sub
66
66
  rf_protocols/codes/somfy/rts/__init__.py
67
67
  rf_protocols/commands/__init__.py
68
+ rf_protocols/commands/ev1527.py
69
+ rf_protocols/commands/kaku.py
68
70
  rf_protocols/commands/ook.py
69
71
  rf_protocols/commands/pt2262.py
70
72
  rf_protocols/commands/somfy_rts.py
File without changes
File without changes
File without changes