├── .gitignore
├── .img
├── ir_sig_graph.png
├── rickroll.jpg
├── subghz_histogram.png
├── subghz_plot.png
└── try_ir-RC5.png
├── .pylintrc
├── IR
├── .Lego-Train-Remote.png
├── .Midea_rem500.png
├── .Minolta-MN674.png
├── .Roomba_5101IR.png
├── .gen-all-ir.sh
├── .gitignore
├── All-Codes
│ ├── IR-NEC-00-00.ir
│ ├── IR-NEC-02-00.ir
│ ├── IR-NEC-04-00.ir
│ ├── IR-NEC-40-00.ir
│ ├── IR-NEC-50-00.ir
│ ├── IR-NECext-00-00.ir
│ ├── IR-NECext-00-7F.ir
│ ├── IR-NECext-02-00.ir
│ ├── IR-NECext-84-00.ir
│ ├── IR-NECext-85-00.ir
│ ├── IR-NECext-86-00.ir
│ ├── IR-NECext-EA-00.ir
│ ├── IR-RC5-00-00.ir
│ ├── IR-RC5-03-00.ir
│ ├── IR-RC5-30-00.ir
│ ├── IR-RC6-00-00.ir
│ ├── IR-SIRC-01-00.ir
│ ├── IR-SIRC-10-00.ir
│ ├── IR-SIRC15-1A-00.ir
│ ├── IR-SIRC15-77-00.ir
│ ├── IR-SIRC15-97-00.ir
│ ├── IR-SIRC15-A4-00.ir
│ ├── IR-Samsung32-00-00.ir
│ ├── IR-Samsung32-06-00.ir
│ ├── IR-Samsung32-07-00.ir
│ ├── IR-Samsung32-08-00.ir
│ ├── IR-Samsung32-0B-00.ir
│ ├── IR-Samsung32-0E-00.ir
│ ├── IR-Samsung32-37-07.ir
│ └── README.md
├── Lego_Remote.ir
├── Lego_Train.ir
├── Midea_AC.ir
├── Minolta_MN674.ir
├── README.md
└── Roomba_5101IR.ir
├── LICENSE
├── Makefile
├── README.md
├── ir_gen_all_codes.py
├── ir_plot.py
├── nfc
├── .rick-roll.jpg
├── README.md
└── Rick_Roll.nfc
├── nfc_dict_diff.py
├── nfc_dict_strip.py
├── nfc_flip2prox.py
├── nfc_gen_phone.py
├── nfc_gen_url.py
├── nfc_gen_wifi.py
├── nfc_hexdump.py
├── nfc_prox2flip.py
├── subghz
├── .fan-11T.png
├── .x10-unit.png
├── README.md
├── X10
│ ├── X10_All-LIGHTS-OFF.png
│ ├── X10_All-LIGHTS-OFF.sub
│ ├── X10_All-LIGHTS-ON.sub
│ ├── X10_All-OFF.sub
│ └── X10_All-ON.sub
├── fan_bruteforce
│ ├── fan_brute-High.sub
│ ├── fan_brute-Lit.sub
│ ├── fan_brute-Low.sub
│ ├── fan_brute-Med.sub
│ └── fan_brute-Off.sub
└── firecracker_spec.txt
├── subghz_create_dat.py
├── subghz_decode_presets.py
├── subghz_gen_cmd.py
├── subghz_histogram.py
├── subghz_insteon.py
├── subghz_ook_to_sub.py
├── subghz_plot.py
├── subghz_preset_gen.py
├── subghz_secplusv1.py
├── subghz_secplusv2.py
├── subghz_x10.py
├── test_dat
├── README.md
├── Raw_Sample.sub
├── mf-classic-1k-23AD7C86.json
└── setting_user
└── url2flipnfc.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | .DS_Store
7 |
8 | secplus/
9 | repos/
10 |
11 | # C extensions
12 | *-reg
13 |
14 | /*.bin
15 | *.sav
16 | *-sav
17 | *-sav?
18 |
19 | /*-debug
20 |
21 | /x10
22 | /*.nfc
23 |
24 | *Notes
25 | /*.json
26 |
27 | *.so
28 |
29 | secv2-*.sub
30 |
31 | *--
32 | *---
33 |
34 | /*.sub
35 |
36 | touch_tunes-*
37 | *.swp
38 |
39 | Sav/
40 |
41 | # Distribution / packaging
42 | .Python
43 | build/
44 | develop-eggs/
45 | dist/
46 | downloads/
47 | eggs/
48 | .eggs/
49 | lib/
50 | lib64/
51 | parts/
52 | sdist/
53 | var/
54 | wheels/
55 | pip-wheel-metadata/
56 | share/python-wheels/
57 | *.egg-info/
58 | .installed.cfg
59 | *.egg
60 | MANIFEST
61 |
62 | # PyInstaller
63 | # Usually these files are written by a python script from a template
64 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
65 | *.manifest
66 | *.spec
67 |
68 | # Installer logs
69 | pip-log.txt
70 | pip-delete-this-directory.txt
71 |
72 | # Unit test / coverage reports
73 | htmlcov/
74 | .tox/
75 | .nox/
76 | .coverage
77 | .coverage.*
78 | .cache
79 | nosetests.xml
80 | coverage.xml
81 | *.cover
82 | *.py,cover
83 | .hypothesis/
84 | .pytest_cache/
85 |
86 | # Translations
87 | *.mo
88 | *.pot
89 |
90 | # Django stuff:
91 | *.log
92 | local_settings.py
93 | db.sqlite3
94 | db.sqlite3-journal
95 |
96 | # Flask stuff:
97 | instance/
98 | .webassets-cache
99 |
100 | # Scrapy stuff:
101 | .scrapy
102 |
103 | # Sphinx documentation
104 | docs/_build/
105 |
106 | # PyBuilder
107 | target/
108 |
109 | # Jupyter Notebook
110 | .ipynb_checkpoints
111 |
112 | # IPython
113 | profile_default/
114 | ipython_config.py
115 |
116 | # pyenv
117 | .python-version
118 |
119 | # pipenv
120 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
121 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
122 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
123 | # install all needed dependencies.
124 | #Pipfile.lock
125 |
126 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
127 | __pypackages__/
128 |
129 | # Celery stuff
130 | celerybeat-schedule
131 | celerybeat.pid
132 |
133 | # SageMath parsed files
134 | *.sage.py
135 |
136 | # Environments
137 | .env
138 | .venv
139 | env/
140 | venv/
141 | ENV/
142 | env.bak/
143 | venv.bak/
144 |
145 | # Spyder project settings
146 | .spyderproject
147 | .spyproject
148 |
149 | # Rope project settings
150 | .ropeproject
151 |
152 | # mkdocs documentation
153 | /site
154 |
155 | # mypy
156 | .mypy_cache/
157 | .dmypy.json
158 | dmypy.json
159 |
160 | # Pyre type checker
161 | .pyre/
162 |
--------------------------------------------------------------------------------
/.img/ir_sig_graph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evilpete/flipper_toolbox/c3b5fc19d0eacd7da4fff6f21f100b9b76446150/.img/ir_sig_graph.png
--------------------------------------------------------------------------------
/.img/rickroll.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evilpete/flipper_toolbox/c3b5fc19d0eacd7da4fff6f21f100b9b76446150/.img/rickroll.jpg
--------------------------------------------------------------------------------
/.img/subghz_histogram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evilpete/flipper_toolbox/c3b5fc19d0eacd7da4fff6f21f100b9b76446150/.img/subghz_histogram.png
--------------------------------------------------------------------------------
/.img/subghz_plot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evilpete/flipper_toolbox/c3b5fc19d0eacd7da4fff6f21f100b9b76446150/.img/subghz_plot.png
--------------------------------------------------------------------------------
/.img/try_ir-RC5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evilpete/flipper_toolbox/c3b5fc19d0eacd7da4fff6f21f100b9b76446150/.img/try_ir-RC5.png
--------------------------------------------------------------------------------
/.pylintrc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | [MASTER]
5 | ignore=flipperzero_protobuf_compiled
6 |
7 | [FORMAT]
8 | max-line-length=110
9 | max-module-lines=2000
10 |
11 | [MESSAGES CONTROL]
12 | disable=invalid-name,missing-docstring
13 |
14 | [DESIGN]
15 | max-branches=30
16 | max-attributes=15
17 | max-locals=30
18 | max-public-methods=30
19 | max-statements=90
20 |
21 |
--------------------------------------------------------------------------------
/IR/.Lego-Train-Remote.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evilpete/flipper_toolbox/c3b5fc19d0eacd7da4fff6f21f100b9b76446150/IR/.Lego-Train-Remote.png
--------------------------------------------------------------------------------
/IR/.Midea_rem500.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evilpete/flipper_toolbox/c3b5fc19d0eacd7da4fff6f21f100b9b76446150/IR/.Midea_rem500.png
--------------------------------------------------------------------------------
/IR/.Minolta-MN674.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evilpete/flipper_toolbox/c3b5fc19d0eacd7da4fff6f21f100b9b76446150/IR/.Minolta-MN674.png
--------------------------------------------------------------------------------
/IR/.Roomba_5101IR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evilpete/flipper_toolbox/c3b5fc19d0eacd7da4fff6f21f100b9b76446150/IR/.Roomba_5101IR.png
--------------------------------------------------------------------------------
/IR/.gen-all-ir.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | dest='IR/All-Codes'
4 |
5 | test ${PWD##*/} == 'IR' && dest='All-Codes'
6 | test -t 1 && echo "dest dir: ${dest}"
7 |
8 | mkdir -p ${dest}
9 | pushd ${dest}
10 |
11 | ../../ir_gen_all_codes.py NEC 00 00
12 | ../../ir_gen_all_codes.py NEC 02 00
13 | ../../ir_gen_all_codes.py NEC 04 00
14 | ../../ir_gen_all_codes.py NEC 40 00
15 | ../../ir_gen_all_codes.py NEC 50 00
16 | ../../ir_gen_all_codes.py NECext 00 00
17 | ../../ir_gen_all_codes.py NECext 00 7F
18 | ../../ir_gen_all_codes.py NECext 02 00
19 | ../../ir_gen_all_codes.py NECext 84 00
20 | ../../ir_gen_all_codes.py NECext 85 00
21 | ../../ir_gen_all_codes.py NECext 86 00
22 | ../../ir_gen_all_codes.py NECext EA 00
23 | ../../ir_gen_all_codes.py RC5 00 00
24 | ../../ir_gen_all_codes.py RC5 03 00
25 | ../../ir_gen_all_codes.py RC5 30 00
26 | ../../ir_gen_all_codes.py RC6 00 00
27 | ../../ir_gen_all_codes.py SIRC 01 00 00 00
28 | ../../ir_gen_all_codes.py SIRC 10 00 00 00
29 | ../../ir_gen_all_codes.py SIRC15 1A 00 00 00
30 | ../../ir_gen_all_codes.py SIRC15 77 00 00 00
31 | ../../ir_gen_all_codes.py SIRC15 97 00 00 00
32 | ../../ir_gen_all_codes.py SIRC15 A4 00 00 00
33 | ../../ir_gen_all_codes.py Samsung32 00 00 00 00
34 | ../../ir_gen_all_codes.py Samsung32 06 00 00 00
35 | ../../ir_gen_all_codes.py Samsung32 07 00 00 00
36 | ../../ir_gen_all_codes.py Samsung32 08 00 00 00
37 | ../../ir_gen_all_codes.py Samsung32 0B 00 00 00
38 | ../../ir_gen_all_codes.py Samsung32 0E 00 00 00
39 | ../../ir_gen_all_codes.py Samsung32 37 07 00 00
40 | popd
41 |
--------------------------------------------------------------------------------
/IR/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | *.py
3 |
--------------------------------------------------------------------------------
/IR/All-Codes/IR-RC5-00-00.ir:
--------------------------------------------------------------------------------
1 | Filetype: IR signals file
2 | Version: 1
3 | # generated with flipper_toolbox
4 | #
5 | name: Code_063
6 | type: parsed
7 | protocol: RC5
8 | address: 00 00 00 00
9 | command: 3F 00 00 00
10 | #
11 | name: Code_062
12 | type: parsed
13 | protocol: RC5
14 | address: 00 00 00 00
15 | command: 3E 00 00 00
16 | #
17 | name: Code_061
18 | type: parsed
19 | protocol: RC5
20 | address: 00 00 00 00
21 | command: 3D 00 00 00
22 | #
23 | name: Code_060
24 | type: parsed
25 | protocol: RC5
26 | address: 00 00 00 00
27 | command: 3C 00 00 00
28 | #
29 | name: Code_059
30 | type: parsed
31 | protocol: RC5
32 | address: 00 00 00 00
33 | command: 3B 00 00 00
34 | #
35 | name: Code_058
36 | type: parsed
37 | protocol: RC5
38 | address: 00 00 00 00
39 | command: 3A 00 00 00
40 | #
41 | name: Code_057
42 | type: parsed
43 | protocol: RC5
44 | address: 00 00 00 00
45 | command: 39 00 00 00
46 | #
47 | name: Code_056
48 | type: parsed
49 | protocol: RC5
50 | address: 00 00 00 00
51 | command: 38 00 00 00
52 | #
53 | name: Code_055
54 | type: parsed
55 | protocol: RC5
56 | address: 00 00 00 00
57 | command: 37 00 00 00
58 | #
59 | name: Code_054
60 | type: parsed
61 | protocol: RC5
62 | address: 00 00 00 00
63 | command: 36 00 00 00
64 | #
65 | name: Code_053
66 | type: parsed
67 | protocol: RC5
68 | address: 00 00 00 00
69 | command: 35 00 00 00
70 | #
71 | name: Code_052
72 | type: parsed
73 | protocol: RC5
74 | address: 00 00 00 00
75 | command: 34 00 00 00
76 | #
77 | name: Code_051
78 | type: parsed
79 | protocol: RC5
80 | address: 00 00 00 00
81 | command: 33 00 00 00
82 | #
83 | name: Code_050
84 | type: parsed
85 | protocol: RC5
86 | address: 00 00 00 00
87 | command: 32 00 00 00
88 | #
89 | name: Code_049
90 | type: parsed
91 | protocol: RC5
92 | address: 00 00 00 00
93 | command: 31 00 00 00
94 | #
95 | name: Code_048
96 | type: parsed
97 | protocol: RC5
98 | address: 00 00 00 00
99 | command: 30 00 00 00
100 | #
101 | name: Code_047
102 | type: parsed
103 | protocol: RC5
104 | address: 00 00 00 00
105 | command: 2F 00 00 00
106 | #
107 | name: Code_046
108 | type: parsed
109 | protocol: RC5
110 | address: 00 00 00 00
111 | command: 2E 00 00 00
112 | #
113 | name: Code_045
114 | type: parsed
115 | protocol: RC5
116 | address: 00 00 00 00
117 | command: 2D 00 00 00
118 | #
119 | name: Code_044
120 | type: parsed
121 | protocol: RC5
122 | address: 00 00 00 00
123 | command: 2C 00 00 00
124 | #
125 | name: Code_043
126 | type: parsed
127 | protocol: RC5
128 | address: 00 00 00 00
129 | command: 2B 00 00 00
130 | #
131 | name: Code_042
132 | type: parsed
133 | protocol: RC5
134 | address: 00 00 00 00
135 | command: 2A 00 00 00
136 | #
137 | name: Code_041
138 | type: parsed
139 | protocol: RC5
140 | address: 00 00 00 00
141 | command: 29 00 00 00
142 | #
143 | name: Code_040
144 | type: parsed
145 | protocol: RC5
146 | address: 00 00 00 00
147 | command: 28 00 00 00
148 | #
149 | name: Code_039
150 | type: parsed
151 | protocol: RC5
152 | address: 00 00 00 00
153 | command: 27 00 00 00
154 | #
155 | name: Code_038
156 | type: parsed
157 | protocol: RC5
158 | address: 00 00 00 00
159 | command: 26 00 00 00
160 | #
161 | name: Code_037
162 | type: parsed
163 | protocol: RC5
164 | address: 00 00 00 00
165 | command: 25 00 00 00
166 | #
167 | name: Code_036
168 | type: parsed
169 | protocol: RC5
170 | address: 00 00 00 00
171 | command: 24 00 00 00
172 | #
173 | name: Code_035
174 | type: parsed
175 | protocol: RC5
176 | address: 00 00 00 00
177 | command: 23 00 00 00
178 | #
179 | name: Code_034
180 | type: parsed
181 | protocol: RC5
182 | address: 00 00 00 00
183 | command: 22 00 00 00
184 | #
185 | name: Code_033
186 | type: parsed
187 | protocol: RC5
188 | address: 00 00 00 00
189 | command: 21 00 00 00
190 | #
191 | name: Code_032
192 | type: parsed
193 | protocol: RC5
194 | address: 00 00 00 00
195 | command: 20 00 00 00
196 | #
197 | name: Code_031
198 | type: parsed
199 | protocol: RC5
200 | address: 00 00 00 00
201 | command: 1F 00 00 00
202 | #
203 | name: Code_030
204 | type: parsed
205 | protocol: RC5
206 | address: 00 00 00 00
207 | command: 1E 00 00 00
208 | #
209 | name: Code_029
210 | type: parsed
211 | protocol: RC5
212 | address: 00 00 00 00
213 | command: 1D 00 00 00
214 | #
215 | name: Code_028
216 | type: parsed
217 | protocol: RC5
218 | address: 00 00 00 00
219 | command: 1C 00 00 00
220 | #
221 | name: Code_027
222 | type: parsed
223 | protocol: RC5
224 | address: 00 00 00 00
225 | command: 1B 00 00 00
226 | #
227 | name: Code_026
228 | type: parsed
229 | protocol: RC5
230 | address: 00 00 00 00
231 | command: 1A 00 00 00
232 | #
233 | name: Code_025
234 | type: parsed
235 | protocol: RC5
236 | address: 00 00 00 00
237 | command: 19 00 00 00
238 | #
239 | name: Code_024
240 | type: parsed
241 | protocol: RC5
242 | address: 00 00 00 00
243 | command: 18 00 00 00
244 | #
245 | name: Code_023
246 | type: parsed
247 | protocol: RC5
248 | address: 00 00 00 00
249 | command: 17 00 00 00
250 | #
251 | name: Code_022
252 | type: parsed
253 | protocol: RC5
254 | address: 00 00 00 00
255 | command: 16 00 00 00
256 | #
257 | name: Code_021
258 | type: parsed
259 | protocol: RC5
260 | address: 00 00 00 00
261 | command: 15 00 00 00
262 | #
263 | name: Code_020
264 | type: parsed
265 | protocol: RC5
266 | address: 00 00 00 00
267 | command: 14 00 00 00
268 | #
269 | name: Code_019
270 | type: parsed
271 | protocol: RC5
272 | address: 00 00 00 00
273 | command: 13 00 00 00
274 | #
275 | name: Code_018
276 | type: parsed
277 | protocol: RC5
278 | address: 00 00 00 00
279 | command: 12 00 00 00
280 | #
281 | name: Code_017
282 | type: parsed
283 | protocol: RC5
284 | address: 00 00 00 00
285 | command: 11 00 00 00
286 | #
287 | name: Code_016
288 | type: parsed
289 | protocol: RC5
290 | address: 00 00 00 00
291 | command: 10 00 00 00
292 | #
293 | name: Code_015
294 | type: parsed
295 | protocol: RC5
296 | address: 00 00 00 00
297 | command: 0F 00 00 00
298 | #
299 | name: Code_014
300 | type: parsed
301 | protocol: RC5
302 | address: 00 00 00 00
303 | command: 0E 00 00 00
304 | #
305 | name: Code_013
306 | type: parsed
307 | protocol: RC5
308 | address: 00 00 00 00
309 | command: 0D 00 00 00
310 | #
311 | name: Code_012
312 | type: parsed
313 | protocol: RC5
314 | address: 00 00 00 00
315 | command: 0C 00 00 00
316 | #
317 | name: Code_011
318 | type: parsed
319 | protocol: RC5
320 | address: 00 00 00 00
321 | command: 0B 00 00 00
322 | #
323 | name: Code_010
324 | type: parsed
325 | protocol: RC5
326 | address: 00 00 00 00
327 | command: 0A 00 00 00
328 | #
329 | name: Code_009
330 | type: parsed
331 | protocol: RC5
332 | address: 00 00 00 00
333 | command: 09 00 00 00
334 | #
335 | name: Code_008
336 | type: parsed
337 | protocol: RC5
338 | address: 00 00 00 00
339 | command: 08 00 00 00
340 | #
341 | name: Code_007
342 | type: parsed
343 | protocol: RC5
344 | address: 00 00 00 00
345 | command: 07 00 00 00
346 | #
347 | name: Code_006
348 | type: parsed
349 | protocol: RC5
350 | address: 00 00 00 00
351 | command: 06 00 00 00
352 | #
353 | name: Code_005
354 | type: parsed
355 | protocol: RC5
356 | address: 00 00 00 00
357 | command: 05 00 00 00
358 | #
359 | name: Code_004
360 | type: parsed
361 | protocol: RC5
362 | address: 00 00 00 00
363 | command: 04 00 00 00
364 | #
365 | name: Code_003
366 | type: parsed
367 | protocol: RC5
368 | address: 00 00 00 00
369 | command: 03 00 00 00
370 | #
371 | name: Code_002
372 | type: parsed
373 | protocol: RC5
374 | address: 00 00 00 00
375 | command: 02 00 00 00
376 | #
377 | name: Code_001
378 | type: parsed
379 | protocol: RC5
380 | address: 00 00 00 00
381 | command: 01 00 00 00
382 | #
383 | name: Code_000
384 | type: parsed
385 | protocol: RC5
386 | address: 00 00 00 00
387 | command: 00 00 00 00
388 |
--------------------------------------------------------------------------------
/IR/All-Codes/IR-RC5-03-00.ir:
--------------------------------------------------------------------------------
1 | Filetype: IR signals file
2 | Version: 1
3 | # generated with flipper_toolbox
4 | #
5 | name: Code_063
6 | type: parsed
7 | protocol: RC5
8 | address: 03 00 00 00
9 | command: 3F 00 00 00
10 | #
11 | name: Code_062
12 | type: parsed
13 | protocol: RC5
14 | address: 03 00 00 00
15 | command: 3E 00 00 00
16 | #
17 | name: Code_061
18 | type: parsed
19 | protocol: RC5
20 | address: 03 00 00 00
21 | command: 3D 00 00 00
22 | #
23 | name: Code_060
24 | type: parsed
25 | protocol: RC5
26 | address: 03 00 00 00
27 | command: 3C 00 00 00
28 | #
29 | name: Code_059
30 | type: parsed
31 | protocol: RC5
32 | address: 03 00 00 00
33 | command: 3B 00 00 00
34 | #
35 | name: Code_058
36 | type: parsed
37 | protocol: RC5
38 | address: 03 00 00 00
39 | command: 3A 00 00 00
40 | #
41 | name: Code_057
42 | type: parsed
43 | protocol: RC5
44 | address: 03 00 00 00
45 | command: 39 00 00 00
46 | #
47 | name: Code_056
48 | type: parsed
49 | protocol: RC5
50 | address: 03 00 00 00
51 | command: 38 00 00 00
52 | #
53 | name: Code_055
54 | type: parsed
55 | protocol: RC5
56 | address: 03 00 00 00
57 | command: 37 00 00 00
58 | #
59 | name: Code_054
60 | type: parsed
61 | protocol: RC5
62 | address: 03 00 00 00
63 | command: 36 00 00 00
64 | #
65 | name: Code_053
66 | type: parsed
67 | protocol: RC5
68 | address: 03 00 00 00
69 | command: 35 00 00 00
70 | #
71 | name: Code_052
72 | type: parsed
73 | protocol: RC5
74 | address: 03 00 00 00
75 | command: 34 00 00 00
76 | #
77 | name: Code_051
78 | type: parsed
79 | protocol: RC5
80 | address: 03 00 00 00
81 | command: 33 00 00 00
82 | #
83 | name: Code_050
84 | type: parsed
85 | protocol: RC5
86 | address: 03 00 00 00
87 | command: 32 00 00 00
88 | #
89 | name: Code_049
90 | type: parsed
91 | protocol: RC5
92 | address: 03 00 00 00
93 | command: 31 00 00 00
94 | #
95 | name: Code_048
96 | type: parsed
97 | protocol: RC5
98 | address: 03 00 00 00
99 | command: 30 00 00 00
100 | #
101 | name: Code_047
102 | type: parsed
103 | protocol: RC5
104 | address: 03 00 00 00
105 | command: 2F 00 00 00
106 | #
107 | name: Code_046
108 | type: parsed
109 | protocol: RC5
110 | address: 03 00 00 00
111 | command: 2E 00 00 00
112 | #
113 | name: Code_045
114 | type: parsed
115 | protocol: RC5
116 | address: 03 00 00 00
117 | command: 2D 00 00 00
118 | #
119 | name: Code_044
120 | type: parsed
121 | protocol: RC5
122 | address: 03 00 00 00
123 | command: 2C 00 00 00
124 | #
125 | name: Code_043
126 | type: parsed
127 | protocol: RC5
128 | address: 03 00 00 00
129 | command: 2B 00 00 00
130 | #
131 | name: Code_042
132 | type: parsed
133 | protocol: RC5
134 | address: 03 00 00 00
135 | command: 2A 00 00 00
136 | #
137 | name: Code_041
138 | type: parsed
139 | protocol: RC5
140 | address: 03 00 00 00
141 | command: 29 00 00 00
142 | #
143 | name: Code_040
144 | type: parsed
145 | protocol: RC5
146 | address: 03 00 00 00
147 | command: 28 00 00 00
148 | #
149 | name: Code_039
150 | type: parsed
151 | protocol: RC5
152 | address: 03 00 00 00
153 | command: 27 00 00 00
154 | #
155 | name: Code_038
156 | type: parsed
157 | protocol: RC5
158 | address: 03 00 00 00
159 | command: 26 00 00 00
160 | #
161 | name: Code_037
162 | type: parsed
163 | protocol: RC5
164 | address: 03 00 00 00
165 | command: 25 00 00 00
166 | #
167 | name: Code_036
168 | type: parsed
169 | protocol: RC5
170 | address: 03 00 00 00
171 | command: 24 00 00 00
172 | #
173 | name: Code_035
174 | type: parsed
175 | protocol: RC5
176 | address: 03 00 00 00
177 | command: 23 00 00 00
178 | #
179 | name: Code_034
180 | type: parsed
181 | protocol: RC5
182 | address: 03 00 00 00
183 | command: 22 00 00 00
184 | #
185 | name: Code_033
186 | type: parsed
187 | protocol: RC5
188 | address: 03 00 00 00
189 | command: 21 00 00 00
190 | #
191 | name: Code_032
192 | type: parsed
193 | protocol: RC5
194 | address: 03 00 00 00
195 | command: 20 00 00 00
196 | #
197 | name: Code_031
198 | type: parsed
199 | protocol: RC5
200 | address: 03 00 00 00
201 | command: 1F 00 00 00
202 | #
203 | name: Code_030
204 | type: parsed
205 | protocol: RC5
206 | address: 03 00 00 00
207 | command: 1E 00 00 00
208 | #
209 | name: Code_029
210 | type: parsed
211 | protocol: RC5
212 | address: 03 00 00 00
213 | command: 1D 00 00 00
214 | #
215 | name: Code_028
216 | type: parsed
217 | protocol: RC5
218 | address: 03 00 00 00
219 | command: 1C 00 00 00
220 | #
221 | name: Code_027
222 | type: parsed
223 | protocol: RC5
224 | address: 03 00 00 00
225 | command: 1B 00 00 00
226 | #
227 | name: Code_026
228 | type: parsed
229 | protocol: RC5
230 | address: 03 00 00 00
231 | command: 1A 00 00 00
232 | #
233 | name: Code_025
234 | type: parsed
235 | protocol: RC5
236 | address: 03 00 00 00
237 | command: 19 00 00 00
238 | #
239 | name: Code_024
240 | type: parsed
241 | protocol: RC5
242 | address: 03 00 00 00
243 | command: 18 00 00 00
244 | #
245 | name: Code_023
246 | type: parsed
247 | protocol: RC5
248 | address: 03 00 00 00
249 | command: 17 00 00 00
250 | #
251 | name: Code_022
252 | type: parsed
253 | protocol: RC5
254 | address: 03 00 00 00
255 | command: 16 00 00 00
256 | #
257 | name: Code_021
258 | type: parsed
259 | protocol: RC5
260 | address: 03 00 00 00
261 | command: 15 00 00 00
262 | #
263 | name: Code_020
264 | type: parsed
265 | protocol: RC5
266 | address: 03 00 00 00
267 | command: 14 00 00 00
268 | #
269 | name: Code_019
270 | type: parsed
271 | protocol: RC5
272 | address: 03 00 00 00
273 | command: 13 00 00 00
274 | #
275 | name: Code_018
276 | type: parsed
277 | protocol: RC5
278 | address: 03 00 00 00
279 | command: 12 00 00 00
280 | #
281 | name: Code_017
282 | type: parsed
283 | protocol: RC5
284 | address: 03 00 00 00
285 | command: 11 00 00 00
286 | #
287 | name: Code_016
288 | type: parsed
289 | protocol: RC5
290 | address: 03 00 00 00
291 | command: 10 00 00 00
292 | #
293 | name: Code_015
294 | type: parsed
295 | protocol: RC5
296 | address: 03 00 00 00
297 | command: 0F 00 00 00
298 | #
299 | name: Code_014
300 | type: parsed
301 | protocol: RC5
302 | address: 03 00 00 00
303 | command: 0E 00 00 00
304 | #
305 | name: Code_013
306 | type: parsed
307 | protocol: RC5
308 | address: 03 00 00 00
309 | command: 0D 00 00 00
310 | #
311 | name: Code_012
312 | type: parsed
313 | protocol: RC5
314 | address: 03 00 00 00
315 | command: 0C 00 00 00
316 | #
317 | name: Code_011
318 | type: parsed
319 | protocol: RC5
320 | address: 03 00 00 00
321 | command: 0B 00 00 00
322 | #
323 | name: Code_010
324 | type: parsed
325 | protocol: RC5
326 | address: 03 00 00 00
327 | command: 0A 00 00 00
328 | #
329 | name: Code_009
330 | type: parsed
331 | protocol: RC5
332 | address: 03 00 00 00
333 | command: 09 00 00 00
334 | #
335 | name: Code_008
336 | type: parsed
337 | protocol: RC5
338 | address: 03 00 00 00
339 | command: 08 00 00 00
340 | #
341 | name: Code_007
342 | type: parsed
343 | protocol: RC5
344 | address: 03 00 00 00
345 | command: 07 00 00 00
346 | #
347 | name: Code_006
348 | type: parsed
349 | protocol: RC5
350 | address: 03 00 00 00
351 | command: 06 00 00 00
352 | #
353 | name: Code_005
354 | type: parsed
355 | protocol: RC5
356 | address: 03 00 00 00
357 | command: 05 00 00 00
358 | #
359 | name: Code_004
360 | type: parsed
361 | protocol: RC5
362 | address: 03 00 00 00
363 | command: 04 00 00 00
364 | #
365 | name: Code_003
366 | type: parsed
367 | protocol: RC5
368 | address: 03 00 00 00
369 | command: 03 00 00 00
370 | #
371 | name: Code_002
372 | type: parsed
373 | protocol: RC5
374 | address: 03 00 00 00
375 | command: 02 00 00 00
376 | #
377 | name: Code_001
378 | type: parsed
379 | protocol: RC5
380 | address: 03 00 00 00
381 | command: 01 00 00 00
382 | #
383 | name: Code_000
384 | type: parsed
385 | protocol: RC5
386 | address: 03 00 00 00
387 | command: 00 00 00 00
388 |
--------------------------------------------------------------------------------
/IR/All-Codes/IR-RC5-30-00.ir:
--------------------------------------------------------------------------------
1 | Filetype: IR signals file
2 | Version: 1
3 | # generated with flipper_toolbox
4 | #
5 | name: Code_063
6 | type: parsed
7 | protocol: RC5
8 | address: 30 00 00 00
9 | command: 3F 00 00 00
10 | #
11 | name: Code_062
12 | type: parsed
13 | protocol: RC5
14 | address: 30 00 00 00
15 | command: 3E 00 00 00
16 | #
17 | name: Code_061
18 | type: parsed
19 | protocol: RC5
20 | address: 30 00 00 00
21 | command: 3D 00 00 00
22 | #
23 | name: Code_060
24 | type: parsed
25 | protocol: RC5
26 | address: 30 00 00 00
27 | command: 3C 00 00 00
28 | #
29 | name: Code_059
30 | type: parsed
31 | protocol: RC5
32 | address: 30 00 00 00
33 | command: 3B 00 00 00
34 | #
35 | name: Code_058
36 | type: parsed
37 | protocol: RC5
38 | address: 30 00 00 00
39 | command: 3A 00 00 00
40 | #
41 | name: Code_057
42 | type: parsed
43 | protocol: RC5
44 | address: 30 00 00 00
45 | command: 39 00 00 00
46 | #
47 | name: Code_056
48 | type: parsed
49 | protocol: RC5
50 | address: 30 00 00 00
51 | command: 38 00 00 00
52 | #
53 | name: Code_055
54 | type: parsed
55 | protocol: RC5
56 | address: 30 00 00 00
57 | command: 37 00 00 00
58 | #
59 | name: Code_054
60 | type: parsed
61 | protocol: RC5
62 | address: 30 00 00 00
63 | command: 36 00 00 00
64 | #
65 | name: Code_053
66 | type: parsed
67 | protocol: RC5
68 | address: 30 00 00 00
69 | command: 35 00 00 00
70 | #
71 | name: Code_052
72 | type: parsed
73 | protocol: RC5
74 | address: 30 00 00 00
75 | command: 34 00 00 00
76 | #
77 | name: Code_051
78 | type: parsed
79 | protocol: RC5
80 | address: 30 00 00 00
81 | command: 33 00 00 00
82 | #
83 | name: Code_050
84 | type: parsed
85 | protocol: RC5
86 | address: 30 00 00 00
87 | command: 32 00 00 00
88 | #
89 | name: Code_049
90 | type: parsed
91 | protocol: RC5
92 | address: 30 00 00 00
93 | command: 31 00 00 00
94 | #
95 | name: Code_048
96 | type: parsed
97 | protocol: RC5
98 | address: 30 00 00 00
99 | command: 30 00 00 00
100 | #
101 | name: Code_047
102 | type: parsed
103 | protocol: RC5
104 | address: 30 00 00 00
105 | command: 2F 00 00 00
106 | #
107 | name: Code_046
108 | type: parsed
109 | protocol: RC5
110 | address: 30 00 00 00
111 | command: 2E 00 00 00
112 | #
113 | name: Code_045
114 | type: parsed
115 | protocol: RC5
116 | address: 30 00 00 00
117 | command: 2D 00 00 00
118 | #
119 | name: Code_044
120 | type: parsed
121 | protocol: RC5
122 | address: 30 00 00 00
123 | command: 2C 00 00 00
124 | #
125 | name: Code_043
126 | type: parsed
127 | protocol: RC5
128 | address: 30 00 00 00
129 | command: 2B 00 00 00
130 | #
131 | name: Code_042
132 | type: parsed
133 | protocol: RC5
134 | address: 30 00 00 00
135 | command: 2A 00 00 00
136 | #
137 | name: Code_041
138 | type: parsed
139 | protocol: RC5
140 | address: 30 00 00 00
141 | command: 29 00 00 00
142 | #
143 | name: Code_040
144 | type: parsed
145 | protocol: RC5
146 | address: 30 00 00 00
147 | command: 28 00 00 00
148 | #
149 | name: Code_039
150 | type: parsed
151 | protocol: RC5
152 | address: 30 00 00 00
153 | command: 27 00 00 00
154 | #
155 | name: Code_038
156 | type: parsed
157 | protocol: RC5
158 | address: 30 00 00 00
159 | command: 26 00 00 00
160 | #
161 | name: Code_037
162 | type: parsed
163 | protocol: RC5
164 | address: 30 00 00 00
165 | command: 25 00 00 00
166 | #
167 | name: Code_036
168 | type: parsed
169 | protocol: RC5
170 | address: 30 00 00 00
171 | command: 24 00 00 00
172 | #
173 | name: Code_035
174 | type: parsed
175 | protocol: RC5
176 | address: 30 00 00 00
177 | command: 23 00 00 00
178 | #
179 | name: Code_034
180 | type: parsed
181 | protocol: RC5
182 | address: 30 00 00 00
183 | command: 22 00 00 00
184 | #
185 | name: Code_033
186 | type: parsed
187 | protocol: RC5
188 | address: 30 00 00 00
189 | command: 21 00 00 00
190 | #
191 | name: Code_032
192 | type: parsed
193 | protocol: RC5
194 | address: 30 00 00 00
195 | command: 20 00 00 00
196 | #
197 | name: Code_031
198 | type: parsed
199 | protocol: RC5
200 | address: 30 00 00 00
201 | command: 1F 00 00 00
202 | #
203 | name: Code_030
204 | type: parsed
205 | protocol: RC5
206 | address: 30 00 00 00
207 | command: 1E 00 00 00
208 | #
209 | name: Code_029
210 | type: parsed
211 | protocol: RC5
212 | address: 30 00 00 00
213 | command: 1D 00 00 00
214 | #
215 | name: Code_028
216 | type: parsed
217 | protocol: RC5
218 | address: 30 00 00 00
219 | command: 1C 00 00 00
220 | #
221 | name: Code_027
222 | type: parsed
223 | protocol: RC5
224 | address: 30 00 00 00
225 | command: 1B 00 00 00
226 | #
227 | name: Code_026
228 | type: parsed
229 | protocol: RC5
230 | address: 30 00 00 00
231 | command: 1A 00 00 00
232 | #
233 | name: Code_025
234 | type: parsed
235 | protocol: RC5
236 | address: 30 00 00 00
237 | command: 19 00 00 00
238 | #
239 | name: Code_024
240 | type: parsed
241 | protocol: RC5
242 | address: 30 00 00 00
243 | command: 18 00 00 00
244 | #
245 | name: Code_023
246 | type: parsed
247 | protocol: RC5
248 | address: 30 00 00 00
249 | command: 17 00 00 00
250 | #
251 | name: Code_022
252 | type: parsed
253 | protocol: RC5
254 | address: 30 00 00 00
255 | command: 16 00 00 00
256 | #
257 | name: Code_021
258 | type: parsed
259 | protocol: RC5
260 | address: 30 00 00 00
261 | command: 15 00 00 00
262 | #
263 | name: Code_020
264 | type: parsed
265 | protocol: RC5
266 | address: 30 00 00 00
267 | command: 14 00 00 00
268 | #
269 | name: Code_019
270 | type: parsed
271 | protocol: RC5
272 | address: 30 00 00 00
273 | command: 13 00 00 00
274 | #
275 | name: Code_018
276 | type: parsed
277 | protocol: RC5
278 | address: 30 00 00 00
279 | command: 12 00 00 00
280 | #
281 | name: Code_017
282 | type: parsed
283 | protocol: RC5
284 | address: 30 00 00 00
285 | command: 11 00 00 00
286 | #
287 | name: Code_016
288 | type: parsed
289 | protocol: RC5
290 | address: 30 00 00 00
291 | command: 10 00 00 00
292 | #
293 | name: Code_015
294 | type: parsed
295 | protocol: RC5
296 | address: 30 00 00 00
297 | command: 0F 00 00 00
298 | #
299 | name: Code_014
300 | type: parsed
301 | protocol: RC5
302 | address: 30 00 00 00
303 | command: 0E 00 00 00
304 | #
305 | name: Code_013
306 | type: parsed
307 | protocol: RC5
308 | address: 30 00 00 00
309 | command: 0D 00 00 00
310 | #
311 | name: Code_012
312 | type: parsed
313 | protocol: RC5
314 | address: 30 00 00 00
315 | command: 0C 00 00 00
316 | #
317 | name: Code_011
318 | type: parsed
319 | protocol: RC5
320 | address: 30 00 00 00
321 | command: 0B 00 00 00
322 | #
323 | name: Code_010
324 | type: parsed
325 | protocol: RC5
326 | address: 30 00 00 00
327 | command: 0A 00 00 00
328 | #
329 | name: Code_009
330 | type: parsed
331 | protocol: RC5
332 | address: 30 00 00 00
333 | command: 09 00 00 00
334 | #
335 | name: Code_008
336 | type: parsed
337 | protocol: RC5
338 | address: 30 00 00 00
339 | command: 08 00 00 00
340 | #
341 | name: Code_007
342 | type: parsed
343 | protocol: RC5
344 | address: 30 00 00 00
345 | command: 07 00 00 00
346 | #
347 | name: Code_006
348 | type: parsed
349 | protocol: RC5
350 | address: 30 00 00 00
351 | command: 06 00 00 00
352 | #
353 | name: Code_005
354 | type: parsed
355 | protocol: RC5
356 | address: 30 00 00 00
357 | command: 05 00 00 00
358 | #
359 | name: Code_004
360 | type: parsed
361 | protocol: RC5
362 | address: 30 00 00 00
363 | command: 04 00 00 00
364 | #
365 | name: Code_003
366 | type: parsed
367 | protocol: RC5
368 | address: 30 00 00 00
369 | command: 03 00 00 00
370 | #
371 | name: Code_002
372 | type: parsed
373 | protocol: RC5
374 | address: 30 00 00 00
375 | command: 02 00 00 00
376 | #
377 | name: Code_001
378 | type: parsed
379 | protocol: RC5
380 | address: 30 00 00 00
381 | command: 01 00 00 00
382 | #
383 | name: Code_000
384 | type: parsed
385 | protocol: RC5
386 | address: 30 00 00 00
387 | command: 00 00 00 00
388 |
--------------------------------------------------------------------------------
/IR/All-Codes/README.md:
--------------------------------------------------------------------------------
1 | # Flipper IR Signals Files #
2 |
3 |
4 |
5 | A Collection of Most (All) possible commands for IR common protocol IR "addresses"
6 |
7 | Good for discovering hidden menus
8 |
9 | generated using [gen_all_ir_codes.py](../../ir_gen_all_codes.py)
10 |
11 |
12 | Addresses chosen from scanning [Flipper-IRDB](https://github.com/Lucaslhm/Flipper-IRDB)
13 |
14 | ---
15 |
16 |
17 | #### [NEC](https://techdocs.altium.com/display/FPGA/NEC+Infrared+Transmission+Protocol) ####
18 |
19 | **[IR-NEC-00-00.ir](IR-NEC-00-00.ir)** All command codes for protocol [NEC](https://techdocs.altium.com/display/FPGA/NEC+Infrared+Transmission+Protocol), address 00 00 00 00
20 |
21 | **[IR-NEC-04-00.ir](IR-NEC-04-00.ir)** NEC, address 04 00 00 00
22 |
23 | **[IR-NEC-40-00.ir](IR-NEC-40-00.ir)** NEC, address 40 00 00 00
24 |
25 | **[IR-NEC-50-00.ir](IR-NEC-50-00.ir)** NEC, address 50 00 00 00
26 |
27 | #### [Extended NEC protocol (NECext)](https://www.sbprojects.net/knowledge/ir/nec.php#:~:text=Extended+NEC+protocol)
28 |
29 | **[IR-NECext-00-00.ir](IR-NECext-00-00.ir)** NECext, address 00 00 00 00
30 |
31 | **[IR-NECext-00-7F.ir](IR-NECext-00-7F.ir)** NECext, address 00 7F 00 00
32 |
33 | **[IR-NECext-02-00.ir](IR-NECext-02-00.ir)** NECext, address 02 00 00 00
34 |
35 | **[IR-NECext-84-00.ir](IR-NECext-84-00.ir)** NECext, address 84 00 00 00
36 |
37 | **[IR-NECext-85-00.ir](IR-NECext-85-00.ir)** NECext, address 85 00 00 00
38 |
39 | **[IR-NECext-86-00.ir](IR-NECext-86-00.ir)** NECext, address 86 00 00 00
40 |
41 | **[IR-NECext-EA-00.ir](IR-NECext-EA-00.ir)** NECext, address EA 00 00 00
42 |
43 | #### [RC5](https://www.mikrocontroller.net/articles/IRMP_-_english#RC5_+_RC5X) ####
44 |
45 | **[IR-RC5-00-00.ir](IR-RC5-00-00.ir)** RC5, address 00 00 00 00
46 |
47 | **[IR-RC5-03-00.ir](IR-RC5-03-00.ir)** RC5, address 03 00 00 00
48 |
49 | **[IR-RC5-30-00.ir](IR-RC5-30-00.ir)** RC5, address 30 00 00 00
50 |
51 | #### [RC6](https://www.mikrocontroller.net/articles/IRMP_-_english#RC6_+_RC6A) ####
52 |
53 | **[IR-RC6-00-00.ir](IR-RC6-00-00.ir)** RC6, address 00 00 00 00
54 |
55 | #### [Sony SIRC](https://www.sbprojects.net/knowledge/ir/sirc.php) ####
56 |
57 | **[IR-SIRC-01-00.ir](IR-SIRC-01-00.ir)** Sony SIRC protocol address 01 00 00 00
58 |
59 | **[IR-SIRC-10-00.ir](IR-SIRC-10-00.ir)** Sony SIRC protocol address 10 00 00 00
60 |
61 | #### [Sony SIRC15](https://www.sbprojects.net/knowledge/ir/sirc.php) ####
62 |
63 | **[IR-SIRC15-1A-00.ir](IR-SIRC15-1A-00.ir)** Sony SIRC15 protocol address 1A 00 00 00
64 |
65 | **[IR-SIRC15-77-00.ir](IR-SIRC15-77-00.ir)** Sony SIRC15 protocol address 77 00 00 00
66 |
67 | **[IR-SIRC15-94-00.ir](IR-SIRC15-94-00.ir)** Sony SIRC15 protocol address 94 00 00 00
68 |
69 | **[IR-SIRC15-A1-00.ir](IR-SIRC15-A1-00.ir)** Sony SIRC15 protocol address A1 00 00 00
70 |
71 | #### [Samsung](https://www.mikrocontroller.net/articles/IRMP_-_english#SAMSUNG32) ####
72 |
73 | **[IR-Samsung32-00-00.ir](IR-Samsung32-00-00.ir)** protocol address 00 00 00 00
74 |
75 | **[IR-Samsung32-06-00.ir](IR-Samsung32-06-00.ir)** protocol address 06 00 00 00
76 |
77 | **[IR-Samsung32-07-00.ir](IR-Samsung32-07-00.ir)** protocol address 07 00 00 00
78 |
79 | **[IR-Samsung32-08-00.ir](IR-Samsung32-08-00.ir)** protocol address 08 00 00 00
80 |
81 | **[IR-Samsung32-0B-00.ir](IR-Samsung32-0B-00.ir)** protocol address 0B 00 00 00
82 |
83 | **[IR-Samsung32-0E-00.ir](IR-Samsung32-0E-00.ir)** protocol address 0E 00 00 00
84 |
85 | **[IR-Samsung32-37-07.ir](IR-Samsung32-37-07.ir)** protocol address 37 07 00 00
86 |
87 |
88 |
--------------------------------------------------------------------------------
/IR/Lego_Remote.ir:
--------------------------------------------------------------------------------
1 | Filetype: IR signals file
2 | Version: 1
3 | #
4 | # LEGO Power Functions Speed Remote Control (8879)
5 | #
6 | name: Left_Button
7 | type: raw
8 | frequency: 38000
9 | duty_cycle: 0.330000
10 | data: 176 1028 174 293 173 241 178 263 177 263 177 265 175 556 180 288 178 237 177 554 176 291 180 234 180 287 179 235 179 263 177 555 176 540 175 100990 179 1025 177 290 176 265 180 260 175 239 175 294 172 532 178 290 181 261 174 530 175 293 173 268 177 263 172 269 176 265 180 526 179 537 178 100854 180 1024 178 262 178 263 177 290 176 264 181 261 174 531 179 262 178 290 176 530 175 266 179 288 178 262 173 268 177 265 180 526 179 536 179 100927 176 1028 179 287 179 262 173 268 177 264 171 244 181 551 174 293 173 269 176 529 176 291 175 266 179 235 179 288 178 264 181 525 179 536 179 100958 177 1027 180 287 179 262 173 241 178 262 178 264 181 550 175 292 174 241 178 553 178 290 176 265 180 234 180 261 174 268 177 555 181 535 180
11 | #
12 | name: Left_Knob_cc
13 | type: raw
14 | frequency: 38000
15 | duty_cycle: 0.330000
16 | data: 181 1024 178 554 176 264 176 264 181 260 175 267 178 554 176 555 176 265 180 262 178 553 178 263 177 264 176 266 179 552 179 263 177 538 177 101158 181 1023 179 553 177 263 177 264 176 264 176 266 179 553 177 554 177 264 181 261 174 557 179 262 178 263 177 265 180 551 174 267 178 537 178 100865 174 1030 177 554 177 265 180 260 175 266 179 262 178 555 176 556 180 261 179 263 177 554 182 260 175 265 180 262 178 553 177 265 180 535 180 101323 181 1024 178 554 176 264 176 264 181 260 175 267 178 554 176 555 176 265 180 262 178 553 177 264 176 264 176 266 179 552 178 264 176 539 176 101293 180 1026 176 555 181 260 175 266 179 261 179 263 177 555 181 551 180 262 178 263 177 555 176 265 180 261 174 267 178 554 176 265 175 540 175
17 | #
18 | name: Left_Knob_cw
19 | type: raw
20 | frequency: 38000
21 | duty_cycle: 0.330000
22 | data: 178 1027 180 551 174 267 178 262 178 263 177 264 181 551 179 552 178 263 177 264 176 556 180 262 178 553 178 265 180 551 174 266 179 245 179 101195 181 1024 178 554 176 264 176 265 180 260 175 267 178 555 181 551 174 266 179 263 177 554 177 266 179 552 179 263 177 555 181 260 175 249 176 101288 177 1027 180 551 179 262 178 262 178 263 177 265 180 552 178 553 177 264 176 265 175 557 178 263 177 555 176 266 179 552 178 263 177 247 178
23 | #
24 | name: Right_Button
25 | type: raw
26 | frequency: 38000
27 | duty_cycle: 0.330000
28 | data: 175 1029 178 262 178 263 177 264 176 264 181 260 175 557 179 263 177 556 175 557 178 262 178 262 178 263 177 264 176 265 180 551 174 251 173 100980 177 1026 176 265 180 260 175 266 179 261 179 263 177 554 182 260 175 558 178 554 176 264 176 264 181 260 175 266 179 262 178 553 177 247 178 100668 177 1026 176 265 180 260 175 266 179 261 179 263 177 554 182 261 174 558 178 554 182 259 176 265 180 261 174 266 179 263 177 554 177 248 177 100916 176 1027 175 265 180 261 174 267 178 262 178 264 176 555 181 261 179 554 177 555 181 260 175 266 179 261 179 262 178 264 176 555 176 249 176 100949 180 1025 177 263 177 264 181 259 176 265 180 261 179 553 178 264 181 552 178 553 177 263 177 264 176 264 181 260 175 267 178 553 177 247 178
29 | #
30 | name: Right_Knob_cc
31 | type: raw
32 | frequency: 38000
33 | duty_cycle: 0.330000
34 | data: 179 1024 178 263 177 263 177 264 176 264 181 261 174 558 178 555 180 551 174 268 177 554 176 264 176 265 180 553 177 554 176 264 181 243 182 123550 177 1028 179 552 178 262 178 263 177 263 177 265 180 552 178 554 177 555 181 261 174 557 179 262 178 263 177 264 181 551 174 266 179 245 179 100820 176 1028 179 553 177 263 177 263 177 264 181 260 175 558 178 555 181 551 174 267 178 553 177 264 176 264 181 261 174 557 178 263 177 247 178 100531 180 1024 178 554 176 264 176 265 180 260 175 267 178 554 181 551 174 557 178 264 176 555 175 265 180 261 174 268 177 554 176 264 176 248 177 100897 177 1027 180 552 178 262 178 262 178 263 177 265 180 552 178 554 177 555 181 261 179 553 177 263 177 263 177 265 180 551 174 267 178 246 178 100898 181 1023 179 553 177 263 177 264 181 259 176 266 179 553 177 556 174 557 178 263 177 554 177 265 180 260 175 267 178 553 177 263 177 248 177
35 | #
36 | name: Right_Knob_cw
37 | type: raw
38 | frequency: 38000
39 | duty_cycle: 0.330000
40 | data: 178 1025 177 264 176 265 180 260 175 266 179 263 177 555 175 557 178 553 177 265 175 556 179 262 178 554 176 556 179 552 178 264 176 539 176 129988 178 1026 181 550 175 266 179 261 179 262 178 263 177 556 174 558 177 554 176 265 175 556 179 262 178 554 176 265 180 551 174 268 177 538 177 101186 175 1030 177 554 176 264 181 260 175 265 180 262 178 554 176 556 179 552 178 263 177 555 180 261 174 557 178 264 181 550 175 293 173 515 179 100900 179 1025 177 554 181 259 176 265 180 261 174 267 178 555 180 552 178 553 177 264 181 551 174 267 178 554 176 265 175 556 179 263 177 538 177 100874 180 1025 177 554 181 260 175 265 180 261 174 268 177 555 180 552 178 553 177 265 180 551 174 268 177 554 176 265 175 557 178 263 177 538 177 101270 178 1027 175 556 179 262 178 262 178 263 177 264 176 557 178 554 181 550 175 267 178 553 177 264 176 556 179 262 178 554 176 265 180 535 180
41 |
--------------------------------------------------------------------------------
/IR/Lego_Train.ir:
--------------------------------------------------------------------------------
1 | Filetype: IR signals file
2 | Version: 1
3 | #
4 | # IR Remote for Lego Train
5 | #
6 | name: Stop
7 | type: raw
8 | frequency: 38000
9 | duty_cycle: 0.330000
10 | data: 175 1029 178 263 177 263 177 264 176 265 180 262 178 553 177 264 181 261 174 557 178 263 177 264 176 265 180 260 175 267 178 555 180 535 179 100783 178 1026 181 260 175 266 179 262 178 262 178 264 181 551 174 266 179 263 177 555 175 265 180 261 179 288 173 242 177 265 175 557 178 537 178 123667 178 1027 180 552 178 288 173 242 177 264 176 265 180 552 178 262 178 290 176 530 174 266 179 288 178 238 176 555 180 262 178 554 176 539 176 101028 201 1004 198 534 201 239 206 235 200 241 204 237 198 534 201 240 205 236 199 533 202 239 206 234 201 241 204 527 198 245 200 532 203 512 203 101108 179 1026 181 551 174 267 178 262 178 263 177 265 180 552 178 263 177 264 181 551 174 267 178 263 177 264 176 556 179 263 177 555 175 541 174 100702 181 1024 178 554 176 291 180 260 175 266 179 263 172 534 181 286 180 263 172 533 182 259 176 292 174 268 177 528 176 265 180 553 177 539 181 100720 178 1026 181 551 174 293 173 242 177 264 176 265 180 578 178 237 177 265 180 577 179 236 178 263 177 265 175 583 173 269 176 556 179 536 178 108292 176 1028 179 262 178 263 177 264 176 265 180 261 179 553 177 263 177 265 175 557 178 289 177 237 177 290 176 239 175 266 179 554 176 539 181 100771 178 1025 177 264 176 264 181 260 175 266 179 263 177 581 180 234 180 262 178 553 177 290 176 265 180 234 180 261 174 268 177 555 180 535 180 100824 178 1025 177 264 176 265 180 287 179 262 173 243 176 555 175 292 174 268 177 528 176 264 181 260 175 293 173 268 177 264 181 525 179 536 179 100885 174 1030 177 263 177 291 175 266 179 262 173 269 176 528 176 291 175 241 178 580 171 270 175 266 179 261 174 267 178 264 181 525 179 536 179 101295 179 1024 178 263 177 264 176 291 175 266 179 237 177 554 181 286 180 236 178 553 177 264 176 265 180 287 179 262 173 243 181 551 174 541 179
11 | #
12 | name: Forward
13 | type: raw
14 | frequency: 38000
15 | duty_cycle: 0.330000
16 | data: 178 1027 180 260 175 293 173 241 178 289 172 244 180 552 178 554 176 290 176 240 174 557 178 289 177 265 180 526 178 554 176 265 175 541 174 101227 224 980 175 292 174 240 179 262 178 289 177 238 176 557 178 553 177 290 181 235 179 552 178 289 172 244 180 553 177 554 176 266 179 536 179 123558 181 1025 177 554 181 286 180 235 179 288 178 264 181 525 179 553 177 289 172 244 180 552 178 262 178 263 177 265 175 556 179 263 177 538 176 132149 177 1027 175 293 173 267 178 237 177 290 176 265 180 527 177 554 181 286 180 235 179 553 177 263 177 265 180 553 177 554 176 266 179 536 179 130708 178 1027 180 551 179 262 178 289 177 237 177 265 180 552 178 553 177 265 180 261 179 552 178 263 177 263 177 265 180 551 179 262 178 538 177 100702 178 1027 180 552 178 262 178 263 177 264 176 265 180 553 177 555 175 265 180 289 177 528 176 264 181 260 180 262 178 554 176 292 179 510 174 100725 181 1024 178 554 181 286 180 261 174 267 178 263 172 535 179 552 178 263 177 291 175 530 179 288 173 242 177 291 180 525 179 289 177 512 177 100728 178 1027 180 552 178 262 178 263 177 290 181 261 174 533 176 555 175 265 180 289 177 528 176 264 181 287 179 263 172 533 182 287 179 510 179 100759 180 1026 181 551 179 262 178 263 177 264 176 265 180 553 177 554 176 265 180 262 178 553 177 265 180 260 175 267 178 553 177 265 175 540 180 111768 177 1027 180 261 179 288 173 268 177 264 181 261 174 532 177 554 176 265 180 261 179 553 177 263 177 265 175 558 177 554 181 287 179 510 179
17 | #
18 | name: Reverse
19 | type: raw
20 | frequency: 38000
21 | duty_cycle: 0.330000
22 | data: 180 1024 178 263 177 264 176 264 181 260 175 267 178 555 180 551 179 262 178 264 176 555 175 267 178 555 180 552 178 553 177 264 181 243 181 100931 178 1026 228 213 232 156 279 162 283 158 277 165 280 505 173 558 177 289 177 239 175 557 178 289 177 530 174 558 177 555 180 260 175 250 174 132676 179 1026 181 551 174 293 173 241 178 289 172 244 180 552 178 553 177 264 176 266 174 557 178 290 176 529 175 293 173 532 177 290 181 217 223 131846 178 1025 177 264 181 286 180 261 174 267 178 237 177 556 179 552 178 263 177 291 175 530 174 267 178 555 180 552 178 554 176 290 176 222 182 100698 178 1025 177 264 181 260 175 292 174 267 178 264 181 525 179 553 177 263 177 291 175 531 179 263 177 556 179 553 177 554 176 291 175 224 180 100726 177 1026 181 260 175 292 174 241 178 263 177 291 175 531 178 554 176 290 176 240 174 558 177 290 176 531 178 554 176 556 179 261 179 246 178 101095 177 1027 180 288 178 263 172 269 176 238 176 266 179 553 177 555 175 292 174 268 177 528 176 292 174 532 177 556 174 557 178 289 177 221 177 101100 174 1030 177 264 176 265 180 260 175 266 179 263 177 556 174 557 178 263 177 265 175 557 178 263 177 556 174 558 177 555 180 260 175 250 174
23 |
--------------------------------------------------------------------------------
/IR/Minolta_MN674.ir:
--------------------------------------------------------------------------------
1 | Filetype: IR signals file
2 | Version: 1
3 | #
4 | # Minolta MN674 Projector
5 | #
6 | name: Power
7 | type: parsed
8 | protocol: NECext
9 | address: 00 DF 00 00
10 | command: 1C E3 00 00
11 | #
12 | name: Flip
13 | type: parsed
14 | protocol: NECext
15 | address: 00 DF 00 00
16 | command: 08 F7 00 00
17 | #
18 | name: Vol_down
19 | type: parsed
20 | protocol: NECext
21 | address: 00 DF 00 00
22 | command: 4F B0 00 00
23 | #
24 | name: Vol_up
25 | type: parsed
26 | protocol: NECext
27 | address: 00 DF 00 00
28 | command: 4B B4 00 00
29 | #
30 | name: Home
31 | type: parsed
32 | protocol: NECext
33 | address: 00 DF 00 00
34 | command: 03 FC 00 00
35 | #
36 | name: Menu
37 | type: parsed
38 | protocol: NECext
39 | address: 00 DF 00 00
40 | command: 18 E7 00 00
41 | #
42 | name: Back
43 | type: parsed
44 | protocol: NECext
45 | address: 00 DF 00 00
46 | command: 0A F5 00 00
47 | #
48 | name: Ok
49 | type: parsed
50 | protocol: NECext
51 | address: 00 DF 00 00
52 | command: 06 F9 00 00
53 | #
54 | name: Up
55 | type: parsed
56 | protocol: NECext
57 | address: 00 DF 00 00
58 | command: 1A E5 00 00
59 | #
60 | name: Left
61 | type: parsed
62 | protocol: NECext
63 | address: 00 DF 00 00
64 | command: 47 B8 00 00
65 | #
66 | name: Right
67 | type: parsed
68 | protocol: NECext
69 | address: 00 DF 00 00
70 | command: 07 F8 00 00
71 | #
72 | name: Down
73 | type: parsed
74 | protocol: NECext
75 | address: 00 DF 00 00
76 | command: 48 B7 00 00
77 | #
78 | name: 1
79 | type: parsed
80 | protocol: NECext
81 | address: 00 DF 00 00
82 | command: 54 AB 00 00
83 | #
84 | name: 2
85 | type: parsed
86 | protocol: NECext
87 | address: 00 DF 00 00
88 | command: 16 E9 00 00
89 | #
90 | name: 3
91 | type: parsed
92 | protocol: NECext
93 | address: 00 DF 00 00
94 | command: 15 EA 00 00
95 | #
96 | name: 4
97 | type: parsed
98 | protocol: NECext
99 | address: 00 DF 00 00
100 | command: 50 AF 00 00
101 | #
102 | name: 5
103 | type: parsed
104 | protocol: NECext
105 | address: 00 DF 00 00
106 | command: 12 ED 00 00
107 | #
108 | name: 6
109 | type: parsed
110 | protocol: NECext
111 | address: 00 DF 00 00
112 | command: 11 EE 00 00
113 | #
114 | name: 7
115 | type: parsed
116 | protocol: NECext
117 | address: 00 DF 00 00
118 | command: 4C B3 00 00
119 | #
120 | name: 8
121 | type: parsed
122 | protocol: NECext
123 | address: 00 DF 00 00
124 | command: 0E F1 00 00
125 | #
126 | name: 9
127 | type: parsed
128 | protocol: NECext
129 | address: 00 DF 00 00
130 | command: 0D F2 00 00
131 | #
132 | name: 0
133 | type: parsed
134 | protocol: NECext
135 | address: 00 DF 00 00
136 | command: 0C F3 00 00
137 | #
138 | name: Mouse
139 | type: parsed
140 | protocol: NECext
141 | address: 00 DF 00 00
142 | command: 42 BD 00 00
143 | #
144 | name: Del
145 | type: parsed
146 | protocol: NECext
147 | address: 00 DF 00 00
148 | command: 10 EF 00 00
149 |
--------------------------------------------------------------------------------
/IR/README.md:
--------------------------------------------------------------------------------
1 | # Flipper IR Signals Files #
2 |
3 | A Collection of IR Signal Files
4 |
5 | ---
6 |
7 |
8 | #### [Minolta_MN674.ir](Minolta_MN674.ir) ####
9 |
10 | Minolta MN674 Projector
11 |
12 | Amazon product link: [Minolta-MN674](https://www.amazon.com/Minolta-MN674/dp/B08WZ3DNL2/)
13 |
14 | ---
15 |
16 |
17 | #### [Roomba_5101IR.ir](Roomba_5101IR.ir) ####
18 |
19 | Roomba 5101IR IRobot Remote Scheduler (older model)
20 |
21 | Amazon product link: [Remote Control 400 or 500 Series](https://www.amazon.com/Ship-Roomba-Scheduler-Remote-Control/dp/B01693B816/) / [Roomba 5101IR IRobot Remote Scheduler](https://www.amazon.com/Roomba-5101IR-IRobot-Remote-Scheduler/dp/B000E7DL9Q)
22 |
23 |
24 | ---
25 |
26 |
27 | #### [Midea_AC_Remote.ir](Midea_AC_Remote.ir) ####
28 |
29 | Midea Air Conditioner Remote Control RG10F2(B2)/BGEFU1
30 |
31 | Product link [Replacement Remote Midea Air Conditioner](https://www.amazon.com/Replace-Control-Projector-0rigjnal-Conditioner/dp/B0BZHZ6MZT)
32 |
33 | ---
34 |
35 |
36 | #### [Lego_Remote.ir](Lego_Remote.ir) ####
37 |
38 | LEGO Power Functions Speed Remote Control (8879)
39 |
40 | Product link [Lego Item #8879](https://www.lego.com/en-us/product/lego-power-functions-ir-speed-remote-control-8879)
41 |
42 | ---
43 |
44 | ### [IR/All-Codes](All-Codes) ###
45 |
46 | A Collection of alll All possible commands for IR common protocol IR "addresses"
47 |
48 | Good for discovering hidden menus
49 |
50 | ( generated using [gen_all_ir_codes.py](../ir_gen_all_codes.py) )
51 |
52 | ---
53 |
--------------------------------------------------------------------------------
/IR/Roomba_5101IR.ir:
--------------------------------------------------------------------------------
1 | Filetype: IR signals file
2 | Version: 1
3 | #
4 | # Roomba Remote
5 | # generated with flipper_toolbox
6 | #
7 | name: Power
8 | type: raw
9 | frequency: 38000
10 | duty_cycle: 0.330000
11 | data: 2743 968 992 2923 965 2949 970 2956 2892 985 974 2941 2897 993 967
12 | #
13 | name: Left
14 | type: raw
15 | frequency: 38000
16 | duty_cycle: 0.330000
17 | data: 2742 980 990 2922 966 2947 993 2907 970 2942 998 2902 2925 977 2921 32418 2740 982 998 2915 973 2940 969 2931 967 2945 974 2926 2922 968 2920 32432 2747 976 994 2919 969 2931 999 2914 974 2926 993 2920 2897 992 2917 32436 2712 998 992 2920 968 2945 995 2905 972 2941 999 2901 2926 975 2923 32417 2741 982 998 2915 973 2940 969 2931 967 2933 996 2916 2921 968 2920
18 | #
19 | name: Right
20 | type: raw
21 | frequency: 38000
22 | duty_cycle: 0.330000
23 | data: 2739 983 1018 2895 972 2940 969 2932 966 2946 973 2927 971 2929 2919 32420 2746 977 993 2921 967 2933 996 2917 971 2929 990 2923 965 2935 2923 32418 2738 972 1018 2908 969 2931 998 2902 965 2948 992 2908 969 2944 2893 32435 2742 983 997 2914 974 2939 969 2931 967 2933 996 2917 970 2930 2927
24 | #
25 | name: Forward
26 | type: raw
27 | frequency: 38000
28 | duty_cycle: 0.330000
29 | data: 2739 969 990 2935 973 2927 992 2921 967 2933 996 2917 2899 990 990 34362 2711 999 991 2935 973 2927 992 2908 969 2944 964 2936 2922 980 1000 34340 2744 979 991 2923 975 2925 994 2920 968 2932 997 2916 2900 990 1000 34340 2744 980 990 2923 965 2949 970 2931 967 2946 973 2928 2919 970 1000 34356 2717 995 995 2917 970 2943 965 2935 973 2940 968 2933 2925 967 992 34363 2720 992 998 2914 974 2966 942 2933 965 2935 994 2920 2896 996 994 34349 2745 980 1000 2912 975 2951 968 2920 978 2949 970 2918 2898 994 996 34346 2738 987 993 2919 969 2958 971 2942 946 2930 999 2914 2892 1000 1001 34340 2745 981 999 2912 976 2925 994 2920 968 2933 996 2917 2899 990 990 34350 2744 980 1000 2913 974 2939 969 2931 967 2946 973 2928 2919 970 999
30 | #
31 | name: Spot
32 | type: raw
33 | frequency: 38000
34 | duty_cycle: 0.330000
35 | data: 2743 978 971 2968 941 2972 947 2927 971 2967 2870 992 998 2941 947 34374 2720 989 970 2943 965 2948 971 2929 969 2943 2894 995 995 2930 968
36 | #
37 | name: Clean
38 | type: raw
39 | frequency: 38000
40 | duty_cycle: 0.330000
41 | data: 2717 978 971 2942 966 2933 965 2948 2899 990 1000 2926 972 2928 970
42 | #
43 | name: Max
44 | type: raw
45 | frequency: 38000
46 | duty_cycle: 0.330000
47 | data: 2737 972 1049 2875 971 2929 990 2923 964 2935 2923 981 968 2944 2924
48 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2022, Peter Shipley
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 |
2 | #
3 | # make lint : runs pylint on all all sripts (default)
4 | #
5 | # make pep8 : run pycodestyle on all script files
6 | #
7 | # make secplus : download the secplus library
8 | #
9 | # make ndeflib ; install ndeflib (NDEF messages) library
10 | #
11 | # make gen-files : (re)generate ir/subghz/nfc data file.
12 | #
13 | # make clone-repos : doanload other repos with useful flipper data files
14 | #
15 |
16 |
17 |
18 | PYCODESTYLE=pycodestyle
19 | PEP8ARG=--ignore=E501,E221,E241,E502,W503
20 |
21 | PYLINT=pylint
22 |
23 |
24 | FILES=subghz_secplusv1.py subghz_secplusv2.py \
25 | nfc_prox2flip.py \
26 | nfc_dict_strip.py nfc_dict_diff.py \
27 | subghz_ook_to_sub.py subghz_x10.py subghz_insteon.py \
28 | ir_gen_all_codes.py ir_plot.py \
29 | nfc_gen_url.py nfc_hexdump.py nfc_prox2flip.py \
30 | subghz_create_dat.py subghz_decode_presets.py subghz_gen_cmd.py \
31 | subghz_histogram.py
32 |
33 | all: pylint
34 |
35 | gen-files: x10-brute ir-brute fan-brute nfc-Rick_Roll
36 |
37 | clone-repos: t119bruteforcer flipperzero-bruteforce CAMEbruteforcer Flipper-IRDB secplus
38 |
39 | lint: pylint
40 |
41 | pylint:
42 | for targ in ${FILES} ; do \
43 | echo $$targ ; \
44 | pylint -E $$targ ; \
45 | done
46 |
47 | # pylint --load-plugins perflint $$targ ; \
48 | # python -m py_compile $$targ ; \
49 | #
50 |
51 |
52 | pep8: pycodestyle
53 |
54 | pycodestyle:
55 | for targ in ${FILES} ; do \
56 | echo $$targ ; \
57 | ${PYCODESTYLE} ${PEP8ARG} $$targ ; \
58 | done
59 |
60 |
61 | # generage brute force files
62 |
63 | ir-brute:
64 | mkdir -p IR/All-Codes
65 | bash IR/.gen-all-ir.sh
66 |
67 | x10-brute:
68 | mkdir -p subghz/X10
69 | ( cd subghz/X10 ; ../../subghz_x10.py -b )
70 |
71 | fan-brute:
72 | mkdir -p subghz/fan
73 | ( cd subghz/fan_bruteforce ; ../../subghz_create_dat.py fan )
74 |
75 | nfc-Rick_Roll:
76 | mkdir -p nfc
77 | ./nfc_gen_url.py https://youtu.be/dQw4w9WgXcQ "Rick Roll" > nfc/Rick_Roll.nfc
78 |
79 | # used 3rd party libraries
80 |
81 | ndeflib:
82 | python3 -m pip install ndeflib
83 |
84 | secplus:
85 | git clone https://github.com/argilo/secplus.git
86 |
87 |
88 | ####
89 |
90 | clean:
91 | @/bin/rm -f *sub *.ir *.nfc touch_tunes-?? *_ON.sub *_OFF.sub X10_All-*.sub secv2-*.sub
92 | @/bin/rm -rf __pycache__ repos
93 |
94 |
95 | # clone usful repos with flipper datafiles
96 |
97 | t119bruteforcer: repos
98 | mkdir -p repos
99 | ( cd repos ; git clone https://github.com/xb8/t119bruteforcer.git )
100 |
101 | flipperzero-bruteforce:
102 | mkdir -p repos
103 | ( cd repos ; git clone https://github.com/tobiabocchi/flipperzero-bruteforce.git )
104 |
105 | CAMEbruteforcer:
106 | mkdir -p repos
107 | ( cd repos ; git clone https://github.com/BitcoinRaven/CAMEbruteforcer.git )
108 |
109 | Flipper-IRDB:
110 | mkdir -p repos
111 | ( cd repos ; git clone https://github.com/logickworkshop/Flipper-IRDB.git )
112 |
113 |
--------------------------------------------------------------------------------
/ir_gen_all_codes.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | ir_gen_all_codes.py (was gen_all_ir_codes.py)
4 | Generates file Flipper IR file will all command codes
5 |
6 | Written By: Peter Shipley github.com/evilpete
7 |
8 | From pkg https://github.com/evilpete/flipper_toolbox
9 | """
10 |
11 | import sys
12 | import time
13 |
14 | MAX_BUTTONS = 256
15 |
16 | CMD_LEN = {
17 | 'RC5': 63, # 6 x40
18 | 'RC5X': 127, # 7 x80
19 | 'RC6': 256, # 8 x100
20 | 'NEC': 255, # 8
21 | # 'NECext': 255, # 16 x10000
22 | 'NECext': 65536, # 16 x10000
23 | 'NEC42': 255, # 8
24 | # 'NEC42ext': 65536, # 16
25 | 'Samsung32': 255, # 8
26 | 'SIRC': 255, # 8
27 | 'SIRC15': 255, # 8
28 | 'SIRC20': 255, # 8
29 | }
30 |
31 | hex_set = set('abcdefABCDEF0123456789')
32 |
33 |
34 | def is_hex_str(s):
35 | return set(s).issubset(hex_set)
36 |
37 |
38 | if __name__ == '__main__':
39 |
40 | if len(sys.argv) < 4:
41 | print(f"""
42 | Requires 3 args:
43 | {sys.argv[0]} PROTO ADDR SUBA
44 |
45 | {sys.argv[0]} NEC 40 00
46 |
47 | Valid proto {' '.join(CMD_LEN.keys())}
48 | """)
49 | sys.exit(1)
50 |
51 | PROTO = sys.argv[1]
52 | ADDR = sys.argv[2].upper()
53 | SUBA = sys.argv[3].upper()
54 |
55 | if PROTO not in CMD_LEN:
56 | print("Invalid IR Protocal")
57 | print(f"Valid proto {' '.join(CMD_LEN.keys())}")
58 | sys.exit(1)
59 |
60 | if ADDR.startswith('0X'):
61 | ADDR = ADDR[2:]
62 |
63 | if SUBA.startswith('0X'):
64 | SUBA = SUBA[2:]
65 |
66 | if not (is_hex_str(ADDR) and int(ADDR, 16) < 255 # noqa
67 | and is_hex_str(SUBA) and int(SUBA, 16) < 255):
68 | print("Invalid IR address or sub-address")
69 | print("Valid values hex 00 -> FF")
70 | sys.exit(1)
71 |
72 | if CMD_LEN[PROTO] > MAX_BUTTONS:
73 | print(f"limiting commands values to under {MAX_BUTTONS -1}")
74 |
75 | out_filen = f"IR-{PROTO}-{ADDR}-{SUBA}.ir"
76 |
77 | print(f"Creating file: {out_filen}")
78 |
79 | with open(out_filen, "w", encoding="utf-8") as fd:
80 |
81 | fd.write("Filetype: IR signals file\nVersion: 1\n")
82 | fd.write("# generated with flipper_toolbox\n")
83 | fd.write(f"# {time.ctime()}\n")
84 |
85 | # 256 button limit ( do you want 65536 buttons? )
86 | cmd_limit_cnt = min(MAX_BUTTONS, CMD_LEN[PROTO])
87 |
88 | for i in range(cmd_limit_cnt, -1, -1):
89 | fd.write(f"#\nname: Code_{i:03d}\ntype: parsed\n"
90 | f"protocol: {PROTO}\naddress: {ADDR} {SUBA} 00 00\n"
91 | f"command: {i & 0xFF:02X} {(i >> 8) & 0xFF:02X} 00 00\n")
92 |
93 | sys.exit(0)
94 |
--------------------------------------------------------------------------------
/ir_plot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 |
4 | ir_plot.py
5 |
6 | plot data from flipper IR raw data save files
7 |
8 | Warning: this is 5 min hack code, use at own risk
9 |
10 | Written By: Peter Shipley github.com/evilpete
11 |
12 | From pkg https://github.com/evilpete/flipper_toolbox
13 |
14 | """
15 |
16 |
17 | import sys
18 | import os
19 | # from statistics import mean
20 | import argparse
21 | from pprint import pprint
22 | import numpy as np
23 | # import pandas as pd
24 | import matplotlib.pyplot as plt
25 |
26 | PRINT_BITS = True # this is a hack
27 |
28 |
29 | def arg_opts():
30 |
31 | parser = argparse.ArgumentParser(add_help=True, # noqa
32 | formatter_class=argparse.RawDescriptionHelpFormatter)
33 |
34 | parser.add_argument('-v', '--verbose', dest="verbose",
35 | default=0,
36 | help='Increase debug verbosity', action='count')
37 |
38 | parser.add_argument("-n", "--name", dest="cmd_name",
39 | default=None,
40 | help="IR Command Name")
41 |
42 | parser.add_argument("-f", "--file", dest="filename",
43 | default=None,
44 | help="IR Filename")
45 |
46 | parser.add_argument("-i", "--invert", dest="invert",
47 | default=False,
48 | action='store_true',
49 | help="Invert Wave plot")
50 |
51 | parser.add_argument("-d", "--dir", dest="destdir",
52 | default=None,
53 | help="Destination")
54 |
55 | parser.add_argument("-o", "--output", dest="out_format",
56 | choices=['png', 'pdf', 'svg'],
57 | default="None",
58 | help="Output Format")
59 |
60 | parser.add_argument("-s", "--screen", dest="screen",
61 | default=False, action='store_true',
62 | help="Display on Screen")
63 |
64 | # data_grp = parser.add_mutually_exclusive_group()
65 |
66 | return parser.parse_known_args()
67 |
68 |
69 | def load_cmd_data(filename):
70 | name = data_str = sig_type = duty_cycle = freq = None
71 |
72 | ret = []
73 | with open(filename, 'r', encoding="utf-8") as fd:
74 |
75 | header = fd.readline().strip()
76 | if header != 'Filetype: IR signals file':
77 | print(f"Error: {filename} is not a 'Flipper IR signals file'")
78 | sys.exit(1)
79 |
80 | for line in fd:
81 |
82 | line = line.strip()
83 |
84 | if not line or line[0] == '#': # skip blank lines
85 | continue
86 |
87 | try:
88 | if line.startswith('name:'):
89 | name = line.split(':')[1].strip()
90 | sig_type = freq = duty_cycle = data_str = None
91 |
92 | if line.startswith('type:'):
93 | sig_type = line.split(':')[1].strip()
94 |
95 | if line.startswith('frequency:'):
96 | freq = line.split(':')[1].strip()
97 |
98 | if line.startswith('duty_cycle:'):
99 | duty_cycle = line.split(':')[1].strip()
100 |
101 | if line.startswith('data:'):
102 | data_str = line.split(':')[1].strip()
103 |
104 | except IndexError:
105 | print("Line format error: {line)")
106 |
107 | if name and sig_type and freq and duty_cycle and data_str:
108 | if sig_type == 'raw':
109 | dat = {
110 | 'name': name,
111 | 'type': sig_type,
112 | 'freq': freq,
113 | 'duty_cycle': duty_cycle,
114 | 'data_str': data_str,
115 | }
116 | ret.append(dat)
117 |
118 | name = sig_type = freq = duty_cycle = data_str = None
119 |
120 | return ret
121 |
122 |
123 | def split_data_str(dat, max_val=15000):
124 |
125 | dat_list = dat.split()
126 | ret = []
127 | cur_dat = []
128 |
129 | # print(f"dat_list: {len(dat_list)}")
130 |
131 | for x in dat_list:
132 | i = int(x)
133 | if i > max_val:
134 | ret.append(cur_dat)
135 | # print(f"cur_dat: {len(cur_dat)}")
136 | cur_dat = []
137 | else:
138 | cur_dat.append(i)
139 |
140 | ret.append(cur_dat)
141 |
142 | return ret
143 |
144 |
145 | LOW_PLOT_VAL = 1
146 | HIGH_PLOT_VAL = 5
147 |
148 |
149 | def convert_dat(dat_list, invert=False, verbose=0): # normalize=0,
150 |
151 | high_val = HIGH_PLOT_VAL
152 | low_val = LOW_PLOT_VAL
153 | # print("== convert_dat")
154 |
155 | if len(dat_list) % 2 != 0:
156 | dat_list.append(0)
157 |
158 | dat_len = len(dat_list)
159 |
160 | if verbose > 1:
161 | print(f"dat_len {dat_len}")
162 |
163 | if invert:
164 | high_val = LOW_PLOT_VAL
165 | low_val = HIGH_PLOT_VAL
166 |
167 | # i_min = 15
168 | # # o_min = 23
169 | # if normalize:
170 | # e = dat_list[2::2]
171 | # i_min = min(e) // 10
172 | # if verbose > 2:
173 | # o = dat_list[3::2]
174 | # print(min(dat_list), mean(dat_list),
175 | # max(dat_list), "\n", dat_list, "\n")
176 | # print(min(e), mean(e), max(e), "\n", e, "\n")
177 | # print(min(o), mean(o), max(o), "\n", o, "\n")
178 | # print("\n\n")
179 |
180 | res = [low_val]
181 | for x in range(0, dat_len, 2):
182 |
183 | i = dat_list[x] # // 10
184 | # if normalize:
185 | # i = (i // i_min) * i_min
186 |
187 | j = int(dat_list[x + 1]) # // 10
188 | # if normalize:
189 | # j = (j // 23) * 26
190 |
191 | # print(f"{x}: {i} {j} {len(res)}")
192 | # res += [LOW_PLOT_VAL] * i
193 | # res += [HIGH_PLOT_VAL] * j
194 |
195 | res += [high_val] * i
196 | res += [low_val] * j
197 | res.append(1)
198 |
199 | # print("\n")
200 | return res
201 |
202 |
203 | # An Experiment
204 | def decode_dat(dat_list, verbose=0):
205 |
206 | dat_len = len(dat_list)
207 | if verbose > 1:
208 | print("== decode_dat")
209 | resA = []
210 | resB = []
211 | i = j = 0
212 | for x in range(0, dat_len, 2):
213 |
214 | i = dat_list[x] # // 10
215 |
216 | j = int(dat_list[x + 1]) # // 10
217 |
218 | A = '1' if i > j else '0'
219 | resA.append(A)
220 | B = '1' if j > 500 else '0'
221 | resB.append(B)
222 |
223 | # if verbose > 1:#test
224 | # print(f"{x:3d}: {i:4d} {j:4d} : {A} {B}")
225 |
226 | if verbose > 1: # test
227 | print(f"A: {resA}")
228 | print(f"B: {resB}")
229 |
230 | # def printbits
231 | # # this method is total hack and only works on a
232 | # if debug or PRINT_BITS:
233 | # # Print Bits
234 | # o = d[1::2]
235 | # avg_val = mean(o)
236 | # bits = ['0' if b < avg_val else '1' for b in o]
237 | # # print(o)
238 | # bit_str = "".join(bits)
239 | # print(bits, bit_str, "{0:02x} {0:d}".format(int(bit_str, 2)))
240 |
241 |
242 | def main():
243 |
244 | filen = 'Test.ir' # None
245 | cmd_name = destdir = None
246 | verbose = 0
247 |
248 | arg, av = arg_opts()
249 | # print("arg", arg, "av=", av)
250 |
251 | disp = False
252 |
253 | if arg.verbose:
254 | verbose = arg.verbose
255 |
256 | # get input filename from argparse or fist arg
257 | if arg.filename:
258 | filen = arg.filename
259 | elif av:
260 | filen = av.pop(0)
261 |
262 | if filen is None:
263 | print('Usage:\n\tir_plot.py ')
264 | sys.exit(0)
265 |
266 | if not os.path.exists(filen):
267 | print(f"file {filen} not found")
268 | sys.exit(0)
269 |
270 | if arg.cmd_name:
271 | cmd_name = arg.cmd_name
272 | elif av:
273 | cmd_name = av.pop(0)
274 |
275 | if arg.destdir:
276 | destdir = arg.destdir
277 | if not os.path.exists(destdir):
278 | os.mkdir(destdir)
279 |
280 | # if arg.out_format in ['png', 'pdf', 'svg']:
281 | # if not os.path.exists(destdir):
282 | # os.mkdir(destdir)
283 |
284 | if arg.screen or arg.out_format not in ['png', 'pdf', 'svg']:
285 | disp = True
286 |
287 | # print("arg", arg, "disp=", disp)
288 |
289 | cmd_data = load_cmd_data(filen)
290 |
291 | # pprint(cmd_data, compact=True)
292 | # print(f"cmd_data len {len(cmd_data)}")
293 |
294 | if cmd_name:
295 | cmd_data = [x for x in cmd_data if cmd_name == x['name']]
296 |
297 | if not cmd_data:
298 | print(f'Was not able to find raw data for "{cmd_name}" in {filen}')
299 | sys.exit()
300 |
301 | if verbose:
302 | print(f"{len(cmd_data)} found in {filen}")
303 |
304 | if destdir is None and arg.out_format in ['png', 'pdf', 'svg']:
305 | if len(cmd_data) == 1:
306 | destdir = '.'
307 | else: # cmd_data is > 1
308 | destdir = os.path.splitext(filen)[0]
309 |
310 | # if verbose:
311 | # print(f"destdir = {destdir}")
312 |
313 | # if not os.path.exists(destdir):
314 | # os.mkdir(destdir)
315 |
316 | for dat in cmd_data:
317 | dat['data'] = split_data_str(dat['data_str'])
318 |
319 | ii = 0
320 | for dat in cmd_data:
321 |
322 | dat_lists = dat['data']
323 | # name = dat['name']
324 |
325 | plt.figure(ii)
326 | ax = plt.gca()
327 | ax.axes.yaxis.set_visible(False)
328 | plt.title(f"IR Signal: {dat['name']}")
329 |
330 | # if verbose > 1:#test
331 | # print(f'\n{ii} {name} == {len(dat_lists)}')
332 |
333 | if verbose > 2:
334 | pprint(dat_lists, indent=4, compact=True)
335 |
336 | list_lenghts = []
337 | conv_dat_lists = []
338 | y_off = 0
339 | for d in dat_lists:
340 |
341 | if verbose > 1:
342 | print('o:', d[1::2])
343 | print('e:', d[0::2])
344 |
345 | print(f"d: {d}")
346 |
347 | # normalize=True,
348 | n_dat = convert_dat(d, invert=arg.invert, verbose=arg.verbose)
349 |
350 | conv_dat_lists.append(n_dat)
351 | list_lenghts.append(len(n_dat))
352 |
353 | if verbose > 1:
354 | print(f"d: {d}")
355 |
356 | # decode_dat(d)
357 |
358 | # print(list_lenghts)
359 |
360 | max_len = max(list_lenghts)
361 | # print(max_len)
362 | plot_x = np.arange(max_len)
363 |
364 | for d in conv_dat_lists:
365 | d_len = len(d)
366 | if d_len < max_len:
367 | ln = max_len - d_len
368 | d += [1] * ln
369 |
370 | plot_y = np.array(d) + (y_off * (HIGH_PLOT_VAL + 1))
371 |
372 | plt.plot(plot_x, plot_y)
373 |
374 | # y_off += HIGH_PLOT_VAL + 1
375 | y_off += 1
376 |
377 | plt.gcf().set_size_inches(6, 1 + (.5 * y_off))
378 |
379 | if arg.out_format == 'png':
380 | if arg.verbose:
381 | print(f'{destdir}/{ii}_{cmd_name}.png y_off={y_off}')
382 | plt.savefig(f'{destdir}/{ii}_{cmd_name}.png', pad_inches=0.3)
383 |
384 | ii += 1
385 |
386 | if disp:
387 | plt.show()
388 |
389 |
390 | if __name__ == '__main__':
391 | main()
392 |
--------------------------------------------------------------------------------
/nfc/.rick-roll.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evilpete/flipper_toolbox/c3b5fc19d0eacd7da4fff6f21f100b9b76446150/nfc/.rick-roll.jpg
--------------------------------------------------------------------------------
/nfc/README.md:
--------------------------------------------------------------------------------
1 | # Flipper Flipper NFC Files #
2 |
3 | A Collection of NFC Device Files
4 |
5 | ---
6 |
7 |
8 | #### [Rick_Roll.nfc](Rick_Roll.nfc) ####
9 |
10 | Flipper NFC device file to emulate a NTAG215 encoded with a Rick Roll URL when scanned
11 |
12 | Contains encoded URL [https://youtu.be/dQw4w9WgXcQ](https://youtu.be/dQw4w9WgXcQ)
13 |
14 | ( generated using [gen_url_nfc.py](../gen_url_nfc.py) )
15 |
16 | ---
17 |
--------------------------------------------------------------------------------
/nfc/Rick_Roll.nfc:
--------------------------------------------------------------------------------
1 | Filetype: Flipper NFC device
2 | Version: 2
3 | # generated with flipper_toolbox
4 | Device type: NTAG215
5 | # UID, ATQA and SAK are common for all formats
6 | UID: 04 10 56 01 74 48 03
7 | ATQA: 44 00
8 | SAK: 00
9 | # Mifare Ultralight specific data
10 | Signature: A5 80 A4 CC A0 C3 A1 F6 8B BE 6F EE 83 A6 B9 EE 36 F8 FB C8 14 5A 23 AA 29 DB 78 56 07 B9 6B 92
11 | Mifare version: 00 04 04 02 01 00 11 03
12 | Counter 0: 0
13 | Tearing 0: 00
14 | Counter 1: 0
15 | Tearing 1: 00
16 | Counter 2: 0
17 | Tearing 2: 00
18 | Pages total: 135
19 | Page 0: 04 10 56 CA
20 | Page 1: 01 74 48 03
21 | Page 2: 3E 48 00 00
22 | Page 3: E1 10 3E 00
23 | Page 4: 03 29 91 01
24 | Page 5: 15 55 04 79
25 | Page 6: 6F 75 74 75
26 | Page 7: 2E 62 65 2F
27 | Page 8: 64 51 77 34
28 | Page 9: 77 39 57 67
29 | Page 10: 58 63 51 51
30 | Page 11: 01 0C 54 02
31 | Page 12: 65 6E 52 69
32 | Page 13: 63 6B 20 52
33 | Page 14: 6F 6C 6C FE
34 | Page 15: 00 00 00 00
35 | Page 16: 00 00 00 00
36 | Page 17: 00 00 00 00
37 | Page 18: 00 00 00 00
38 | Page 19: 00 00 00 00
39 | Page 20: 00 00 00 00
40 | Page 21: 00 00 00 00
41 | Page 22: 00 00 00 00
42 | Page 23: 00 00 00 00
43 | Page 24: 00 00 00 00
44 | Page 25: 00 00 00 00
45 | Page 26: 00 00 00 00
46 | Page 27: 00 00 00 00
47 | Page 28: 00 00 00 00
48 | Page 29: 00 00 00 00
49 | Page 30: 00 00 00 00
50 | Page 31: 00 00 00 00
51 | Page 32: 00 00 00 00
52 | Page 33: 00 00 00 00
53 | Page 34: 00 00 00 00
54 | Page 35: 00 00 00 00
55 | Page 36: 00 00 00 00
56 | Page 37: 00 00 00 00
57 | Page 38: 00 00 00 00
58 | Page 39: 00 00 00 00
59 | Page 40: 00 00 00 00
60 | Page 41: 00 00 00 00
61 | Page 42: 00 00 00 00
62 | Page 43: 00 00 00 00
63 | Page 44: 00 00 00 00
64 | Page 45: 00 00 00 00
65 | Page 46: 00 00 00 00
66 | Page 47: 00 00 00 00
67 | Page 48: 00 00 00 00
68 | Page 49: 00 00 00 00
69 | Page 50: 00 00 00 00
70 | Page 51: 00 00 00 00
71 | Page 52: 00 00 00 00
72 | Page 53: 00 00 00 00
73 | Page 54: 00 00 00 00
74 | Page 55: 00 00 00 00
75 | Page 56: 00 00 00 00
76 | Page 57: 00 00 00 00
77 | Page 58: 00 00 00 00
78 | Page 59: 00 00 00 00
79 | Page 60: 00 00 00 00
80 | Page 61: 00 00 00 00
81 | Page 62: 00 00 00 00
82 | Page 63: 00 00 00 00
83 | Page 64: 00 00 00 00
84 | Page 65: 00 00 00 00
85 | Page 66: 00 00 00 00
86 | Page 67: 00 00 00 00
87 | Page 68: 00 00 00 00
88 | Page 69: 00 00 00 00
89 | Page 70: 00 00 00 00
90 | Page 71: 00 00 00 00
91 | Page 72: 00 00 00 00
92 | Page 73: 00 00 00 00
93 | Page 74: 00 00 00 00
94 | Page 75: 00 00 00 00
95 | Page 76: 00 00 00 00
96 | Page 77: 00 00 00 00
97 | Page 78: 00 00 00 00
98 | Page 79: 00 00 00 00
99 | Page 80: 00 00 00 00
100 | Page 81: 00 00 00 00
101 | Page 82: 00 00 00 00
102 | Page 83: 00 00 00 00
103 | Page 84: 00 00 00 00
104 | Page 85: 00 00 00 00
105 | Page 86: 00 00 00 00
106 | Page 87: 00 00 00 00
107 | Page 88: 00 00 00 00
108 | Page 89: 00 00 00 00
109 | Page 90: 00 00 00 00
110 | Page 91: 00 00 00 00
111 | Page 92: 00 00 00 00
112 | Page 93: 00 00 00 00
113 | Page 94: 00 00 00 00
114 | Page 95: 00 00 00 00
115 | Page 96: 00 00 00 00
116 | Page 97: 00 00 00 00
117 | Page 98: 00 00 00 00
118 | Page 99: 00 00 00 00
119 | Page 100: 00 00 00 00
120 | Page 101: 00 00 00 00
121 | Page 102: 00 00 00 00
122 | Page 103: 00 00 00 00
123 | Page 104: 00 00 00 00
124 | Page 105: 00 00 00 00
125 | Page 106: 00 00 00 00
126 | Page 107: 00 00 00 00
127 | Page 108: 00 00 00 00
128 | Page 109: 00 00 00 00
129 | Page 110: 00 00 00 00
130 | Page 111: 00 00 00 00
131 | Page 112: 00 00 00 00
132 | Page 113: 00 00 00 00
133 | Page 114: 00 00 00 00
134 | Page 115: 00 00 00 00
135 | Page 116: 00 00 00 00
136 | Page 117: 00 00 00 00
137 | Page 118: 00 00 00 00
138 | Page 119: 00 00 00 00
139 | Page 120: 00 00 00 00
140 | Page 121: 00 00 00 00
141 | Page 122: 00 00 00 00
142 | Page 123: 00 00 00 00
143 | Page 124: 00 00 00 00
144 | Page 125: 00 00 00 00
145 | Page 126: 00 00 00 00
146 | Page 127: 00 00 00 00
147 | Page 128: 00 00 00 00
148 | Page 129: 00 00 00 00
149 | Page 130: 00 00 00 BD
150 | Page 131: 04 00 00 FF
151 | Page 132: 00 05 00 00
152 | Page 133: 00 00 00 00
153 | Page 134: 00 00 00 00
154 |
--------------------------------------------------------------------------------
/nfc_dict_diff.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | nfc_dict_diff.py : strip diff dict key files
4 | Written By: Peter Shipley github.com/evilpete
5 |
6 | From pkg https://github.com/evilpete/flipper_toolbox
7 | """
8 |
9 | # Quick script to diff two Flipper NFC dict lists
10 |
11 | #
12 | # nfc_dict_diff.py mf_classic_dict_user.nfc new-mf_classic_dict_user.nfc
13 | #
14 |
15 | import sys
16 |
17 | file1 = sys.argv[1]
18 | file2 = sys.argv[2]
19 |
20 | COL = 6
21 |
22 | print(file1, file2)
23 |
24 | with open(file1, 'r', encoding="utf-8") as fd:
25 | list_A = [line.strip() for line in fd if line[0] != '#' and len(line) > 4]
26 | print("list_A", len(list_A), file1)
27 | set_A = set(list_A)
28 |
29 | with open(file2, 'r', encoding="utf-8") as fd:
30 | list_B = [line.strip() for line in fd if line[0] != '#' and len(line) > 4]
31 | print("list_B", len(list_B), file2)
32 | set_B = set(list_B)
33 |
34 | diff_AB = set_A.difference(set_B)
35 | # print("diff_AB", diff_AB)
36 | print("-------")
37 | print("diff list_A - list_B =", len(diff_AB))
38 |
39 |
40 | print(f"Unique to {file1}")
41 | len_AB = len(diff_AB)
42 | list_AB = sorted(list(diff_AB))
43 | for X in range(1, len_AB, COL):
44 | print(" ".join(list_AB[X:X + COL]))
45 |
46 | diff_BA = set_B.difference(set_A)
47 | # print("diff_BA", diff_BA)
48 | print("-------")
49 | print("diff list_B - list_A =", len(diff_BA))
50 |
51 |
52 | print(f"Unique to {file2}")
53 | len_BA = len(diff_BA)
54 | list_BA = sorted(list(diff_BA))
55 | for X in range(1, len_BA, COL):
56 | print(" ".join(list_BA[X:X + COL]))
57 |
58 | common_AB = set_A.intersection(set_B)
59 | print("-------")
60 | print("Intersection list_A and list_B =", len(common_AB))
61 | list_common = sorted(list(common_AB))
62 | for X in range(1, len_BA, COL):
63 | print(" ".join(list_common[X:X + COL]))
64 |
--------------------------------------------------------------------------------
/nfc_dict_strip.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | """
4 | nfc_dict_strip.py : strip duplicate dict keys
5 | Written By: Peter Shipley github.com/evilpete
6 |
7 | From pkg https://github.com/evilpete/flipper_toolbox
8 | """
9 |
10 | # Quick script to comment out or strip duplicate dict keys
11 |
12 | #
13 | # nfc_dict_strip.py mf_classic_dict.nfc mf_classic_dict_user.nfc > mf_classic_dict_user_unique.nfc
14 | #
15 |
16 | import sys
17 | import time
18 |
19 | file1 = file2 = del_dups = None
20 | _debug = 0
21 |
22 | gen_str = "# Generated with https://github.com/evilpete/flipper_toolbox"
23 |
24 |
25 | def dict_strip(file_1, file_2):
26 |
27 | with open(file_1, 'r', encoding="utf-8") as fd:
28 | list_A = [line.strip().upper() for line in fd if line[0] != '#' and len(line) > 4]
29 | # print("list_A", len(list_A), file_1)
30 | set_A = set(list_A)
31 |
32 | with open(file_2, 'r', encoding="utf-8") as fd:
33 | for line in fd:
34 | if _debug:
35 | print(f">>> {line}", end="", file=sys.stderr)
36 | if line[0] == '#':
37 | if not line.startswith("# Generated "):
38 | print(line, end="")
39 | continue
40 | dat = line[:12].upper()
41 | if _debug:
42 | print("line len =", len(line), file=sys.stderr)
43 | print("DAT len =", len(dat), file=sys.stderr)
44 | if dat in set_A:
45 | if del_dups is None:
46 | print(f"#- {line}", end="")
47 | else:
48 | print(dat)
49 | # print(line, end="")
50 |
51 | print(gen_str)
52 | print(f"# Generated {time.ctime()}")
53 |
54 |
55 | if __name__ == '__main__':
56 |
57 | av = sys.argv[1:]
58 |
59 | if av and av[0] == '-h':
60 | print("Usage:\n\tnfc_dict_strip.py [-d ] dict_file_A dict_file_B > dict_nodups\n")
61 | print("\tremoves duplicate keys, outputing only keys unique to dict_file_B")
62 | sys.exit(0)
63 |
64 | if av and av[0] == '-d':
65 | av.pop(0)
66 | del_dups = True
67 |
68 | if av:
69 | file1 = av.pop(0)
70 | if av:
71 | file2 = av.pop(0)
72 |
73 | if not (file1 and file2):
74 | print("Two filesnames required", file=sys.stderr)
75 | sys.exit(0)
76 |
77 | dict_strip(file1, file2)
78 |
--------------------------------------------------------------------------------
/nfc_flip2prox.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | nfc_flip2prox.py
4 | Written By: Peter Shipley github.com/evilpete
5 |
6 | From pkg https://github.com/evilpete/flipper_toolbox
7 | """
8 |
9 | # pylint: disable=line-too-long
10 |
11 | import os
12 | import sys
13 | import binascii
14 | # import pprint
15 | import json
16 |
17 |
18 | FLIPPER_NFC_FILETYPE = 'Flipper NFC device'
19 | blk_data = []
20 |
21 | _debug = 0
22 |
23 |
24 | def read_data(inFile):
25 |
26 | with open(inFile, 'r', encoding="utf-8") as fd:
27 |
28 | line = fd.readline().strip()
29 |
30 | if line.startswith("Filetype:"):
31 | a = line.split(':', 1)
32 | if not a[1].strip().startswith(FLIPPER_NFC_FILETYPE):
33 | print(f"Error: {inFile} is not a Flipper NFC data file")
34 | if _debug:
35 | print(f">>{line}<<")
36 | sys.exit(1)
37 | else:
38 | print(f"Error: {inFile} is not a Flipper NFC data file")
39 | if _debug:
40 | print(f">>>{line}<<<")
41 | sys.exit(1)
42 |
43 | for line in fd:
44 | line = line.strip()
45 |
46 | if not line or line[0] == '#': # skip blank lines
47 | continue
48 |
49 | if line.startswith("Device type:"):
50 | a = line.split(':', 1)
51 | if not a[1].strip().startswith('Mifare'):
52 | print(f"Error: {inFile} is not a Mifare data file: {a[1].strip()}")
53 | if _debug:
54 | print(f">>>>{line}<<<<")
55 | print(f">>>>{a[0]}<<<<")
56 | print(f">>>>{a[1]}<<<<")
57 | sys.exit(1)
58 |
59 | if line.startswith("Block"):
60 | b = line.split(':', 1)[1].strip()
61 | blk_data.append(b.split())
62 |
63 |
64 | def write_mct_data(outFile):
65 | i = 0
66 | sec_cnt = 0
67 | with open(outFile, 'w', encoding="utf-8") as fd:
68 | for b in blk_data:
69 | if (i % 4) == 0:
70 | print(f"+Sector: {sec_cnt}", file=fd)
71 | sec_cnt += 1
72 | i += 1
73 | # hex_str = "".join(b).upper()
74 | # print(hex_str, file=fd)
75 | print("".join(b).upper(), file=fd)
76 |
77 |
78 | def write_bin_data(outFile):
79 | with open(outFile + '.bin', 'wb') as fd:
80 | for b in blk_data:
81 | # hex_str = "".join(b)
82 | # bin_str = binascii.unhexlify(hex_str)
83 | # fd.write(bin_str)
84 | fd.write(binascii.unhexlify("".join(b)))
85 |
86 |
87 | # {"id":"5b4bebb8-f32e-4021-a65b-f73f9fc29e6e","uid":"1C CA 76 A0","sak":8,"atqa":[0,4],"name":"chaminade","tag":3,"color":"#ff5722",
88 | # [ str(int(x, 16)) for x in aa]
89 | # [1C CA 76 A0] 00 [08] 04 00 03 4D 90 1A FF 4A 0A 1D
90 | def write_cham_data(outFile):
91 |
92 | dat_s = blk_data[0]
93 | dat_i = [int(x, 16) for x in dat_s]
94 | j_data = [[]] * 256
95 | dat = {
96 | "id": ' '.join(dat_s[:4]),
97 | "uid": ' '.join(dat_s[:4]),
98 | "sak": dat_i[5],
99 | "atqa": [dat_i[7], dat_i[6]],
100 | "name": out_filen,
101 | "tag": 3,
102 | "color": "#ff5722",
103 | "data": j_data,
104 | }
105 |
106 | i = 0
107 | for b in blk_data:
108 | j_data[i] = [int(x, 16) for x in b]
109 | i += 1
110 |
111 | # with open(outFile + ".pp", 'w', encoding="utf-8") as fd:
112 | # pprint.pprint(dat, stream=fd)
113 |
114 | with open(outFile + "_cm.json", 'w', encoding="utf-8") as fd:
115 | json.dump(dat, fd)
116 |
117 |
118 | def write_eml_data(outFile):
119 | with open(outFile + ".eml", 'w', encoding="utf-8") as fd:
120 | for b in blk_data:
121 | hex_str = "".join(b).upper()
122 | print(hex_str, file=fd)
123 |
124 |
125 | def write_mcj_data(outFile):
126 | b_data = {}
127 | dat = {
128 | "Created": "MifareClassicTool",
129 | "FileType": "mfcard",
130 | "blocks": b_data
131 | }
132 |
133 | i = 0
134 | for b in blk_data:
135 | b_data[str(i)] = "".join(b).upper()
136 | i += 1
137 |
138 | with open(outFile + "_mct.json", 'w', encoding="utf-8") as fd:
139 | json.dump(dat, fd, indent=2)
140 |
141 |
142 | write_funcs = {
143 | 'eml': (write_eml_data, "proxmark emulator"), # proxmark emulator
144 | 'bin': (write_bin_data, "proxmark/Chameleon bin format"), # proxmark
145 | 'mct': (write_mct_data, "MIFARE Classic Tool"), # MIFARE Classic Tool
146 | 'mfj': (write_mcj_data, "MIFARE Classic Tool Json"), # MIFARE Classic Tool Json
147 | 'json': (write_cham_data, "proxmark/Chameleonn Json format"), # Chameleon Json format
148 | }
149 |
150 | if __name__ == '__main__':
151 |
152 | out_format = None
153 | out_filen = None
154 |
155 | av = sys.argv[1:]
156 |
157 | if av and av[0] == '-h':
158 | print("\tnfc_conv.py [-f output_format] input_filename [output_filename]")
159 |
160 | print("\n\tValid formats:")
161 | for k, v in write_funcs.items():
162 | print(f"\t\t{k}:\t{v[1]}")
163 | sys.exit(1)
164 |
165 |
166 | if av and av[0] == '-f':
167 | av.pop(0)
168 | if av:
169 | out_format = av.pop(0)
170 | else:
171 | print("Error: '-f' option requires format name")
172 | sys.exit(1)
173 | if out_format not in write_funcs:
174 | print("Error: unknown format")
175 | print(" Known Formats:", " ".join(write_funcs.keys()))
176 | sys.exit(1)
177 |
178 | if av:
179 | in_filen = av.pop(0)
180 | else:
181 | print("Error: missing input filename")
182 | sys.exit(1)
183 |
184 | if av:
185 | fn = av.pop(0)
186 | out_info = os.path.splitext(fn)
187 | out_format = out_info[1][1:]
188 | out_filen = out_info[0]
189 | else:
190 | out_filen = os.path.splitext(in_filen)[0]
191 |
192 | if _debug:
193 | print(f"in file: {in_filen}")
194 | print(f"out file: {out_filen}")
195 | print(f"out format: {out_format}")
196 |
197 | read_data(in_filen)
198 |
199 | if out_format in write_funcs:
200 | write_funcs[out_format][0](out_filen)
201 | else:
202 | print(f"unknown output format {out_format}")
203 |
204 | # write_eml_data(out_filen)
205 |
--------------------------------------------------------------------------------
/nfc_gen_phone.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | Generates NFC with a telephone number and saves to a Flipper NFC "save" file
4 | No Guarantees.
5 |
6 | ./nfc_gen_phone.py +375296049766 +1
7 | requires ndeflib
8 |
9 | Original Code by: Peter Shipley github.com/evilpete
10 | Modified by: Sage https://github.com/misusage
11 |
12 | From pkg https://github.com/evilpete/flipper_toolbox
13 | """
14 |
15 | import sys
16 | try:
17 | import ndef
18 | except ImportError as e:
19 | print("Failed to import ndef")
20 | print("https://github.com/nfcpy/ndeflib")
21 | sys.exit(0)
22 |
23 | # for debuging
24 | verbose = 0
25 |
26 | nfc_header = """Filetype: Flipper NFC device
27 | Version: 2
28 | # generated with flipper_toolbox
29 | Device type: NTAG215
30 | # UID, ATQA and SAK are common for all formats
31 | UID: 04 10 56 01 74 48 03
32 | ATQA: 44 00
33 | SAK: 00
34 | # Mifare Ultralight specific data
35 | Signature: A5 80 A4 CC A0 C3 A1 F6 8B BE 6F EE 83 A6 B9 EE 36 F8 FB C8 14 5A 23 AA 29 DB 78 56 07 B9 6B 92
36 | Mifare version: 00 04 04 02 01 00 11 03
37 | Counter 0: 0
38 | Tearing 0: 00
39 | Counter 1: 0
40 | Tearing 1: 00
41 | Counter 2: 0
42 | Tearing 2: 00
43 | Pages total: 135
44 | """
45 |
46 | data_static = [
47 | 0x04, 0x10, 0x56, 0xCA, # 01 serial number
48 | 0x01, 0x74, 0x48, 0x03, # 02 serial number
49 | 0x3E, 0x48, 0x00, 0x00, # 03 serial number, internal, lock bytes, lock bytes
50 | 0xE1, 0x10, 0x3E, 0x00, # 04 Capability Container
51 | ]
52 |
53 | conf_pages = [
54 | 0x00, 0x00, 0x00, 0xBD, # 130
55 | 0x04, 0x00, 0x00, 0xFF, # 131
56 | 0x00, 0x05, 0x00, 0x00, # 132
57 | 0x00, 0x00, 0x00, 0x00, # 133
58 | 0x00, 0x00, 0x00, 0x00, # 134
59 | ]
60 |
61 |
62 | def print_nfc_sub(t_data, file=sys.stdout):
63 |
64 | print(nfc_header, end='', file=file)
65 |
66 | p = 0
67 | for x in range(0, 540, 4):
68 | print(f"Page {p}: {t_data[x]:02X} {t_data[x + 1]:02X} "
69 | f"{t_data[x + 2]:02X} {t_data[x + 3]:02X}", file=file)
70 | p = p + 1
71 |
72 |
73 | def write_nfc_sub(t_data):
74 |
75 | print(nfc_header, end='', file=f)
76 |
77 | p = 0
78 | for x in range(0, 540, 4):
79 | print(f"Page {p}: {t_data[x]:02X} {t_data[x + 1]:02X} "
80 | f"{t_data[x + 2]:02X} {t_data[x + 3]:02X}", file=f)
81 | p = p + 1
82 |
83 |
84 | def gen_nfc_sub(tag_data):
85 |
86 | tag_message = []
87 | data_list = []
88 |
89 | for x in tag_data:
90 | if x[0] == 'url':
91 | tag_message.append(ndef.UriRecord(x[1]))
92 |
93 | if verbose:
94 | print(x, file=sys.stderr)
95 | print(tag_message[-1:], file=sys.stderr)
96 |
97 | buf = b"".join((ndef.message_encoder(tag_message)))
98 |
99 | m_len = len(buf)
100 |
101 | if verbose:
102 | print("buf", m_len, hex(m_len), buf, file=sys.stderr)
103 |
104 | data_list.extend(data_static)
105 | data_list.append(3) # Message Flags
106 | data_list.append(m_len) # Type Length
107 | data_list.extend(list(buf))
108 |
109 | data_list.append(0xFE) # end of Data
110 |
111 | data_len = len(data_list)
112 |
113 | if verbose:
114 | print("data_list", data_len, data_list, file=sys.stderr)
115 |
116 | x = 520 - data_len
117 | data_list.extend([0] * x)
118 | data_list.extend(conf_pages)
119 |
120 | return data_list
121 |
122 |
123 | if __name__ == '__main__':
124 |
125 | filename = "call-me.nfc"
126 | telstr = "tel:"
127 | arg_data = []
128 |
129 | for a in sys.argv[1:]:
130 | if a.isdigit():
131 |
132 | for b in sys.argv[2:]:
133 | if b.startswith("+"):
134 | a = b + a
135 | else:
136 | exit
137 |
138 | a = str(telstr) + a #add the tel: nfc code
139 | arg_data.append(("url", a))
140 |
141 | #for i in arg_data:
142 | # print(i, end = ' ')
143 | #print("\n")
144 | else:
145 | exit
146 |
147 | if not arg_data:
148 | print("requires two URL arguments\n"
149 | "Please provide phone number with area code THEN the +country-code.\n"
150 | f"{sys.argv[0]} 12345679876 +1")
151 | sys.exit()
152 |
153 | nfc_data = gen_nfc_sub(arg_data)
154 |
155 | print_nfc_sub(nfc_data)
156 |
157 | if verbose:
158 | for i in arg_data:
159 | print(i[0],i[1])
160 | print_nfc_sub(nfc_data)
161 | else:
162 | with open(filename, mode='w') as f:
163 | write_nfc_sub(nfc_data)
164 | print("\nDone! NFC File has been created: " + filename)
165 |
166 | sys.exit()
167 |
--------------------------------------------------------------------------------
/nfc_gen_url.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | Generates NFC with URL address data and outputs Flipper NFC "save" file
4 | this is a 5 min hack, No Guarantees
5 |
6 | ./nfc_gen_url.py https://youtu.be/dQw4w9WgXcQ "Rick Roll" > rickroll.nfc
7 |
8 | requires ndeflib
9 |
10 | Written By: Peter Shipley github.com/evilpete
11 |
12 | From pkg https://github.com/evilpete/flipper_toolbox
13 | """
14 |
15 | import sys
16 | import time
17 |
18 | try:
19 | import ndef
20 | except ImportError as e:
21 | print("Failed to import ndef")
22 | print("https://github.com/nfcpy/ndeflib")
23 | sys.exit(0)
24 |
25 | # make sure output is utf-8
26 | sys.stdout.reconfigure(encoding='utf-8')
27 |
28 | # for debuging
29 | verbose = 0
30 |
31 | nfc_header = (f"""Filetype: Flipper NFC device
32 | Version: 2
33 | # generated with flipper_toolbox
34 | # {time.ctime()}
35 | Device type: NTAG215
36 | # UID, ATQA and SAK are common for all formats
37 | UID: 04 10 56 01 74 48 03
38 | ATQA: 44 00
39 | SAK: 00
40 | # Mifare Ultralight specific data
41 | Signature: A5 80 A4 CC A0 C3 A1 F6 8B BE 6F EE 83 A6 B9 EE 36 F8 FB C8 14 5A 23 AA 29 DB 78 56 07 B9 6B 92
42 | Mifare version: 00 04 04 02 01 00 11 03
43 | Counter 0: 0
44 | Tearing 0: 00
45 | Counter 1: 0
46 | Tearing 1: 00
47 | Counter 2: 0
48 | Tearing 2: 00
49 | Pages total: 135
50 | """)
51 |
52 | data_static = [
53 | 0x04, 0x10, 0x56, 0xCA, # 01 serial number
54 | 0x01, 0x74, 0x48, 0x03, # 02 serial number
55 | 0x3E, 0x48, 0x00, 0x00, # 03 serial number, internal, lock bytes, lock bytes
56 | 0xE1, 0x10, 0x3E, 0x00, # 04 Capability Container
57 | ]
58 |
59 | conf_pages = [
60 | 0x00, 0x00, 0x00, 0xBD, # 130
61 | 0x04, 0x00, 0x00, 0xFF, # 131
62 | 0x00, 0x05, 0x00, 0x00, # 132
63 | 0x00, 0x00, 0x00, 0x00, # 133
64 | 0x00, 0x00, 0x00, 0x00, # 134
65 | ]
66 |
67 |
68 | def print_nfc_sub(t_data, file=sys.stdout):
69 |
70 | print(nfc_header, end='', file=file)
71 |
72 | p = 0
73 | for x in range(0, 540, 4):
74 | print(f"Page {p}: {t_data[x]:02X} {t_data[x + 1]:02X} "
75 | f"{t_data[x + 2]:02X} {t_data[x + 3]:02X}", file=file)
76 | p = p + 1
77 |
78 |
79 | def gen_nfc_sub(tag_data):
80 |
81 | tag_message = []
82 | data_list = []
83 |
84 | for x in tag_data:
85 | if x[0] == 'txt':
86 | tag_message.append(ndef.TextRecord(x[1], "en"))
87 | elif x[0] == 'url':
88 | tag_message.append(ndef.UriRecord(x[1]))
89 |
90 | if verbose:
91 | print(x, file=sys.stderr)
92 | print(tag_message[-1:], file=sys.stderr)
93 |
94 | buf = b"".join((ndef.message_encoder(tag_message)))
95 |
96 | m_len = len(buf)
97 |
98 | if verbose:
99 | print("buf", m_len, hex(m_len), buf, file=sys.stderr)
100 |
101 | data_list.extend(data_static)
102 | data_list.append(3) # Message Flags
103 | if m_len < 255:
104 | data_list.append(m_len) # Type Length
105 | else:
106 | data_list.append(0xFF)
107 | lenStr = hex(m_len)[2:].rjust(4, "0")
108 | data_list.append(int(lenStr[0:2], 16))
109 | data_list.append(int(lenStr[2:4], 16))
110 | data_list.extend(list(buf))
111 |
112 | data_list.append(0xFE) # end of Data
113 |
114 | data_len = len(data_list)
115 |
116 | if verbose:
117 | print("data_list", data_len, data_list, file=sys.stderr)
118 |
119 | x = 520 - data_len
120 | data_list.extend([0] * x)
121 | data_list.extend(conf_pages)
122 |
123 | return data_list
124 |
125 |
126 | # url_str = "https://youtu.be/dQw4w9WgXcQ"
127 | # title_str = "Rick Roll"
128 |
129 | if __name__ == '__main__':
130 |
131 | arg_data = []
132 |
133 | for a in sys.argv[1:]:
134 | if a.startswith("http"):
135 | arg_data.append(("url", a))
136 | else:
137 | arg_data.append(("txt", a))
138 |
139 | if not arg_data:
140 | print("requires at least one URL argument\n"
141 | "Please provide URL and optional Title\n\n"
142 | f"{sys.argv[0]} : https://some.url 'Title'")
143 | sys.exit()
144 |
145 | nfc_data = gen_nfc_sub(arg_data)
146 |
147 | print_nfc_sub(nfc_data)
148 |
149 | sys.exit()
150 |
--------------------------------------------------------------------------------
/nfc_gen_wifi.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | Generates NFC with WiFi network data and saves to a Flipper NFC "save" file
4 | No Guarantees.
5 |
6 | ./nfc_gen_wifi.py
7 | requires ndeflib
8 |
9 | Original Code by: Peter Shipley github.com/evilpete
10 | Modified by: Sage https://github.com/misusage
11 |
12 | From pkg https://github.com/evilpete/flipper_toolbox
13 | """
14 |
15 | import sys
16 | try:
17 | import ndef
18 | except ImportError as e:
19 | print("Failed to import ndef")
20 | print("https://github.com/nfcpy/ndeflib")
21 | sys.exit(0)
22 |
23 | # for debuging
24 | verbose = 0
25 |
26 | nfc_header = """Filetype: Flipper NFC device
27 | Version: 2
28 | # generated with flipper_toolbox
29 | Device type: NTAG215
30 | # UID, ATQA and SAK are common for all formats
31 | UID: 04 10 56 01 74 48 03
32 | ATQA: 44 00
33 | SAK: 00
34 | # Mifare Ultralight specific data
35 | Signature: A5 80 A4 CC A0 C3 A1 F6 8B BE 6F EE 83 A6 B9 EE 36 F8 FB C8 14 5A 23 AA 29 DB 78 56 07 B9 6B 92
36 | Mifare version: 00 04 04 02 01 00 11 03
37 | Counter 0: 0
38 | Tearing 0: 00
39 | Counter 1: 0
40 | Tearing 1: 00
41 | Counter 2: 0
42 | Tearing 2: 00
43 | Pages total: 135
44 | """
45 |
46 | data_static = [
47 | 0x04, 0x10, 0x56, 0xCA, # 01 serial number
48 | 0x01, 0x74, 0x48, 0x03, # 02 serial number
49 | 0x3E, 0x48, 0x00, 0x00, # 03 serial number, internal, lock bytes, lock bytes
50 | 0xE1, 0x10, 0x3E, 0x00, # 04 Capability Container
51 | ]
52 |
53 | conf_pages = [
54 | 0x00, 0x00, 0x00, 0xBD, # 130
55 | 0x04, 0x00, 0x00, 0xFF, # 131
56 | 0x00, 0x05, 0x00, 0x00, # 132
57 | 0x00, 0x00, 0x00, 0x00, # 133
58 | 0x00, 0x00, 0x00, 0x00, # 134
59 | ]
60 |
61 | def print_nfc_sub(t_data, file=sys.stdout):
62 |
63 | print(nfc_header, end='', file=file)
64 |
65 | p = 0
66 | for x in range(0, 540, 4):
67 | print(f"Page {p}: {t_data[x]:02X} {t_data[x + 1]:02X} "
68 | f"{t_data[x + 2]:02X} {t_data[x + 3]:02X}", file=file)
69 | p = p + 1
70 |
71 |
72 | def write_nfc_sub(t_data):
73 |
74 | print(nfc_header, end='', file=f)
75 |
76 | p = 0
77 | for x in range(0, 540, 4):
78 | print(f"Page {p}: {t_data[x]:02X} {t_data[x + 1]:02X} "
79 | f"{t_data[x + 2]:02X} {t_data[x + 3]:02X}", file=f)
80 | p = p + 1
81 |
82 |
83 | def gen_nfc_sub(tag_data):
84 |
85 | mac = "FF:FF:FF:FF:FF:FF"
86 | data_list = []
87 | credential = ndef.wifi.Credential()
88 | credential.set_attribute('network-index', 1)
89 |
90 | for x in tag_data:
91 | if x[0] == 'ssid':
92 | ssidStr = bytes(x[1], encoding="utf-8")
93 | credential.set_attribute(x[0], ssidStr)
94 | elif x[0] == 'authentication-type':
95 | credential.set_attribute(x[0], x[1])
96 | elif x[0] == 'encryption-type':
97 | credential.set_attribute(x[0], x[1])
98 | elif x[0] == 'network-key':
99 | keyStr = bytes(x[1], encoding="utf-8")
100 | credential.set_attribute(x[0], keyStr)
101 | elif x[0] == 'mac-address':
102 | mac = bytes.fromhex(mac.replace(':', ''))
103 | credential.set_attribute(x[0], mac)
104 |
105 | record = ndef.wifi.WifiSimpleConfigRecord()
106 | record.name = 'my config token'
107 | record.set_attribute('credential', credential)
108 |
109 | for x in tag_data:
110 | if x[0] == 'rf-bands':
111 | record.set_attribute(x[0], x[1])
112 |
113 | buf = b"".join((ndef.message_encoder([record])))
114 | m_len = len(buf)
115 |
116 | data_list.extend(data_static)
117 | data_list.append(3) # Message Flags
118 | data_list.append(m_len) # Type Length
119 | data_list.extend(list(buf))
120 | data_list.append(0xFE) # end of Data
121 |
122 | data_len = len(data_list)
123 |
124 | if verbose:
125 | print("Verbose Mode ON")
126 | for b in tag_data:
127 | print(b, file=sys.stderr)
128 | print("Broadcast Mac: " + str(mac))
129 | print("WiFi Credential Token: " + str(credential))
130 | print(record)
131 | print("Buffer:", m_len, hex(m_len), buf, file=sys.stderr)
132 | print("Data List:", data_len, data_list, file=sys.stderr)
133 |
134 | x = 520 - data_len
135 | data_list.extend([0] * x)
136 | data_list.extend(conf_pages)
137 |
138 | return data_list
139 |
140 |
141 | if __name__ == '__main__':
142 |
143 | filename = "WiFi.nfc"
144 | arg_data = []
145 |
146 | print("NFC WiFi Tag Generator for the Flipper Zero\n"
147 | "###########################################\n")
148 | ssid = input("What is the SSID?: ")
149 | arg_data.append(("ssid", ssid))
150 |
151 | print("Choose an Authentication Type:")
152 | authChoice = input("Enter 1 for WPA/WPA2-Personal\nEnter 2 for WPA/WPA2-Enterprise (might not work)\n> ")
153 | if authChoice == "1":
154 | auth = "WPA2-Personal"
155 | arg_data.append(("authentication-type", auth))
156 | elif authChoice == "2":
157 | auth = "WPA2-Enterprise"
158 | arg_data.append(("authentication-type", auth))
159 | else:
160 | print("ERROR: You typed something else. Exiting...")
161 | sys.exit()
162 |
163 | print("\nChoose an Encryption Type:")
164 | encChoice = input("Enter 1 for AES (Select this option if you don't know)\nEnter 2 for TKIP\n> ")
165 | if encChoice == "1":
166 | encryption = "AES"
167 | arg_data.append(("encryption-type", encryption))
168 | elif encChoice == "2":
169 | encryption = "TKIP"
170 | arg_data.append(("encryption-type", encryption))
171 | else:
172 | print("ERROR: You typed something else. Exiting...")
173 | sys.exit()
174 |
175 | password = input("\nWhat is the WiFi Password?: ")
176 | arg_data.append(("network-key", password))
177 |
178 | print("\nWhat WiFi Band is the network operating on?:")
179 | bandChoice = input("Enter 1 for 2.4GHz\nEnter 2 for 5.0GHz\n> ")
180 | if bandChoice == "1":
181 | band = "2.4GHz"
182 | arg_data.append(("rf-bands", band))
183 | elif bandChoice == "2":
184 | band = "5.0GHz"
185 | arg_data.append(("rf-bands", band))
186 | else:
187 | print("ERROR: You typed something else. Exiting...")
188 | sys.exit()
189 |
190 | nfc_data = gen_nfc_sub(arg_data)
191 |
192 | if verbose:
193 | for i in arg_data:
194 | print(i[0],i[1])
195 | print_nfc_sub(nfc_data)
196 | else:
197 | with open(filename, mode='w') as f:
198 | write_nfc_sub(nfc_data)
199 | print("\nCreated " + filename)
200 |
201 | sys.exit()
202 |
--------------------------------------------------------------------------------
/nfc_hexdump.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | Adds int and hex to RFID HEX dump
4 | [a 2 min script]
5 |
6 | nfc_hexdump.py file.nfc
7 |
8 | Written By: Peter Shipley github.com/evilpete
9 |
10 | From pkg https://github.com/evilpete/flipper_toolbox
11 | """
12 | # In
13 | # Page 4: 03 29 91 01
14 | # Page 5: 15 55 04 79
15 | # Page 6: 6F 75 74 75
16 | # Page 7: 2E 62 65 2F
17 |
18 | # Out
19 | # Page 4: 03 29 91 01 # - ) - - 3 41 145 1
20 | # Page 5: 15 55 04 79 # - U - y 21 85 4 121
21 | # Page 6: 6F 75 74 75 # o u t u 111 117 116 117
22 | # Page 7: 2E 62 65 2F # . b e / 46 98 101 47
23 |
24 | import sys
25 |
26 | A = []
27 |
28 | Chr = True # print as ascii char
29 | Dec = False # print as decimal
30 | Bin = True # print as binary
31 | Rev = False # reverse bit order
32 |
33 | av = sys.argv[1:]
34 |
35 | if av[0][0] == '-':
36 | Chr = Dec = Bin = Rev = False
37 |
38 | while av[0][0] == '-':
39 | arg = av.pop(0)
40 |
41 | if arg == '-r':
42 | Rev = True
43 | elif arg == '-b':
44 | Bin = True
45 | elif arg == '-d':
46 | Dec = True
47 | elif arg == '-c':
48 | Chr = True
49 |
50 |
51 | filename = av.pop(0)
52 | with open(filename, encoding="utf-8") as fd:
53 | header = fd.readline().strip()
54 | if header != 'Filetype: Flipper NFC device':
55 | print(f"Error: {filename} is not a 'Flipper NFC' sample file'")
56 | # sys.exit(1)
57 | for line in fd:
58 | a = line.split()
59 | if a[0] in ["Page", "Block"]:
60 | out_list = []
61 | # b = [int(x, 16) for x in a[2:]]
62 | if Rev:
63 | b = [00 if x == '??' else int(f"{int(x, 16):08b}"[::-1], 2) for x in a[2:]]
64 | else:
65 | b = [00 if x == '??' else int(x, 16) for x in a[2:]]
66 |
67 | if Chr:
68 | # b = [int(a[2], 16), int(a[3], 16), int(a[4], 16), int(a[5], 16)]
69 | c = ["-" if x < 32 or x > 126 else chr(x) for x in b]
70 | d = " ".join(c)
71 | out_list.append(d)
72 |
73 | if Dec:
74 | e = [f"{x:3d}" for x in b]
75 | f = " ".join(e) + ' '
76 | out_list.append(f)
77 |
78 | if Bin:
79 | # e = "{:3d} {:3d} {:3d} {:3d}".format(*b)
80 | g = " ".join([f"{x:08b}" for x in b])
81 | out_list.append(g)
82 |
83 | # print(line.rstrip(), '# ', d, '\t', f, '\t', g)
84 | print(line.rstrip(), '#\t', ' '.join(out_list))
85 | # print(e)
86 | # A.extend(e)
87 | else:
88 | print(line, end='')
89 |
90 | # print("".join(A))
91 |
--------------------------------------------------------------------------------
/nfc_prox2flip.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | """
4 | Reads: proxmark3 MiFare json dump files
5 | Outputs: Flipper NFC compatable format
6 |
7 | nfc_prox2flip.py test_dat/mf-classic-1k-23AD7C86.json > mfc1k-23AD7C86.nfc
8 |
9 | Written By: Peter Shipley github.com/evilpete
10 |
11 | From pkg https://github.com/evilpete/flipper_toolbox
12 | """
13 |
14 | import sys
15 | import time
16 | import json
17 |
18 |
19 | # Nfc device type can be UID, Mifare Ultralight, Mifare Classic, Bank card
20 | # ATQA SAK
21 | CARD_TYPE = {
22 | ("0400", "08"): "Mifare Classic", # 1k
23 | ("0200", "18"): "Mifare Classic", # 1k
24 | ("0400", "09"): "Mifare Mini",
25 | ("4400", "00"): "Mifare Ultralight", # "NTAG213" "NTAG216"
26 | ("4400", "20"): "Bank card",
27 | ("4403", "20"): "Mifare DESFire",
28 | }
29 |
30 |
31 | def convert_dat(in_dat):
32 | """
33 | Take a parsed proxmark json dump arg
34 | returns list in Flipper NFC compatable format
35 | """
36 |
37 | # output list
38 | out_dat = []
39 |
40 | x = in_dat["Card"]
41 |
42 | # Guess card type by looking at ATQA/SAK combo
43 | j = (x["ATQA"], x["SAK"])
44 |
45 | t = CARD_TYPE.get(j, x["UID"])
46 |
47 | # this is a hack to generate Key maps
48 | # should add code to actually parse "SectorKeys"
49 | y = len(in_dat["SectorKeys"])
50 | s = int("1" * y, 2)
51 | ska = skb = f"{s:016X}"
52 |
53 | out_dat.append(
54 | f"""
55 | Filetype: Flipper NFC device
56 | Version: 2
57 | # generated with flipper_toolbox
58 | # {time.ctime()}
59 | # Nfc device type can be UID, Mifare Ultralight, Mifare Classic, Bank card
60 | Device type: {t}
61 | # UID, ATQA and SAK are common for all formats
62 | UID: {x['UID'][0:2]} {x['UID'][2:4]} {x['UID'][4:6]} {x['UID'][6:8]}
63 | ATQA: {x['ATQA'][0:2]} {x['ATQA'][2:4]}
64 | SAK: {x['SAK']}
65 | # Mifare Classic specific data
66 | Mifare Classic type: 1K
67 | Data format version: 1
68 | # Key map is the bit mask indicating valid key in each sector
69 | Key A map: {ska}
70 | Key B map: {skb}
71 | # Mifare Classic blocks"""
72 | )
73 |
74 | # Loop through blocks spliting data into 1 byte pieces
75 | for k, v in in_dat["blocks"].items():
76 | b = " ".join([v[i: i + 2] for i in range(0, len(v), 2)])
77 | out_dat.append(f"Block {k}: {b}")
78 |
79 | return out_dat
80 |
81 |
82 | if __name__ == "__main__":
83 | in_filename = "test_dat/mf-classic-1k-23AD7C86.json"
84 |
85 | if len(sys.argv) >= 2:
86 | in_filename = sys.argv[1]
87 |
88 | with open(in_filename, encoding="utf-8") as fd:
89 | input_dat = json.load(fd)
90 |
91 | output_list = convert_dat(input_dat)
92 |
93 | print("\n".join(output_list))
94 |
95 | sys.exit()
96 |
--------------------------------------------------------------------------------
/subghz/.fan-11T.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evilpete/flipper_toolbox/c3b5fc19d0eacd7da4fff6f21f100b9b76446150/subghz/.fan-11T.png
--------------------------------------------------------------------------------
/subghz/.x10-unit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evilpete/flipper_toolbox/c3b5fc19d0eacd7da4fff6f21f100b9b76446150/subghz/.x10-unit.png
--------------------------------------------------------------------------------
/subghz/README.md:
--------------------------------------------------------------------------------
1 | # Flipper Flipper SubGhz Files #
2 |
3 | A Collection of Signal Files
4 |
5 | ---
6 |
7 |
8 | #### [fan_bruteforce](fan_bruteforce) ####
9 |
10 | Brute Force RF code for Harbor Breeze Fan Remote Control
11 | Model FAN-11T FAN-35T FAN-53T
12 |
13 | Amazon product link: [Harbor Breeze Fan Remote Control](https://www.amazon.com/Ceiling-Control-Replacement-Hampton-KUJCE9103/)
14 |
15 | ( generated using [create_sub_dat.py](../create_sub_dat.py) )
16 |
17 | ---
18 |
19 |
20 |
21 | #### X10 All ON / OFF (bruteforce) ####
22 |
23 | Send All-OFF or ALL-ON for every possible housecode (A -> P)
24 |
25 | [X10_All-OFF.sub](X10/X10_All-OFF.sub) : Send All-OFF for all housecodes
26 |
27 | [X10_All-ON.sub](X10/X10_All-ON.sub) : Send All-ON for all housecodes
28 |
29 | ( generated using [subghz_x10.py](../subghz_x10.py) )
30 |
31 | ---
32 |
33 |
34 |
--------------------------------------------------------------------------------
/subghz/X10/X10_All-LIGHTS-OFF.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evilpete/flipper_toolbox/c3b5fc19d0eacd7da4fff6f21f100b9b76446150/subghz/X10/X10_All-LIGHTS-OFF.png
--------------------------------------------------------------------------------
/subghz_create_dat.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Based heavily on jinschoi/create_sub.py
4 | # https://gist.github.com/jinschoi/f39dbd82e4e3d99d32ab6a9b8dfc2f55
5 | #
6 | # Peter Shipley github.com/evilpete
7 | # From pkg https://github.com/evilpete/flipper_toolbox
8 | #
9 | # Added:
10 | # Fan Control + Brute force pin
11 | # FSK support
12 | #
13 |
14 | import sys
15 | import os
16 | import time
17 | from typing import Iterable, Union, Any
18 |
19 | # pylint: disable=unspecified-encoding,too-many-arguments,too-many-locals,unused-argument
20 |
21 | # freq: frequency in Hz
22 | # zerolen: length of space bit in us
23 | # onelen: length of mark bit in us
24 | # repeats: number of times to repeat sequence
25 | # pause: time to wait in us between sequences
26 | # bits: string of ones and zeros to represent sequence
27 |
28 | _verbose = 0
29 |
30 | # listed in Firmware but not avalible (yet)
31 | # FuriHalSubGhzPresetMSK99_97KbAsync
32 | # FuriHalSubGhzPresetGFSK9_99KbAsync
33 |
34 | # Preset: FuriHalSubGhzPreset2FSKDev238Async
35 | # Preset: FuriHalSubGhzPreset2FSKDev476Async
36 | # Preset: FuriHalSubGhzPresetOok270Async
37 | # Preset: FuriHalSubGhzPresetOok650Async
38 |
39 | CommentText = "generated with flipper_toolbox"
40 |
41 |
42 | def gen_sub(freq, zerolen, onelen, repeats, pause, bits, modu='Ook', srate=650, comment_text=CommentText):
43 |
44 | res = f"""Filetype: Flipper SubGhz RAW File
45 | Version: 1
46 | # {comment_text}
47 | # {time.ctime()}
48 | Frequency: {freq}
49 | Preset: FuriHalSubGhzPreset{modu}{srate}Async
50 | Protocol: RAW
51 | """
52 |
53 | zerolen_off = zerolen % 1
54 | onelen_off = onelen % 1
55 | delta_off = 0.0
56 |
57 | zerolen = int(zerolen)
58 | onelen = int(onelen)
59 |
60 | if pause == 0:
61 | # Pause must be non-zero.
62 | pause = zerolen
63 |
64 | data = []
65 | prevbit = None
66 | prevbitlen = 0
67 | for bit in bits:
68 | if prevbit and prevbit != bit:
69 | data.append(prevbitlen)
70 | prevbitlen = 0
71 |
72 | if bit == '1':
73 | delta_off += onelen_off
74 | prevbitlen += onelen
75 | if delta_off > 1:
76 | prevbitlen += 1
77 | delta_off -= 1
78 | else:
79 | delta_off += zerolen_off
80 | prevbitlen -= zerolen
81 | if delta_off > 1:
82 | prevbitlen -= 1
83 | delta_off -= 1
84 |
85 | prevbit = bit
86 |
87 | if prevbit == '1':
88 | data.append(prevbitlen)
89 | data.append(-pause)
90 | else:
91 | data.append(prevbitlen - pause)
92 |
93 | # data = (data * repeats)[:-1] # Drop the last pause.
94 | datalines = []
95 | for i in range(0, len(data), 512):
96 | batch = [str(n) for n in data[i:i + 512]]
97 | datalines.append(f'RAW_Data: {" ".join(batch)}')
98 | res += '\n'.join(datalines)
99 |
100 | return res
101 |
102 |
103 | # From Wikipedia
104 | def de_bruijn(k: Union[Iterable[Any], int], n: int) -> str:
105 | """de Bruijn sequence for alphabet k
106 | and subsequences of length n.
107 | """
108 | # Two kinds of alphabet input: an integer expands
109 | # to a list of integers as the alphabet..
110 | if isinstance(k, int):
111 | alphabet = list(map(str, range(k)))
112 | else:
113 | # While any sort of list becomes used as it is
114 | alphabet = k
115 | k = len(k)
116 |
117 | a = [0] * k * n
118 | sequence = []
119 |
120 | def db(t, p):
121 | if t > n:
122 | if n % p == 0:
123 | sequence.extend(a[1:p + 1])
124 | else:
125 | a[t] = a[t - p]
126 | db(t + 1, p)
127 | for j in range(a[t - p] + 1, k):
128 | a[t] = j
129 | db(t + 1, t)
130 |
131 | db(1, 1)
132 | return "".join(alphabet[i] for i in sequence)
133 |
134 |
135 | def debruijn(freq, zerolen, onelen, encoding, bitlen, alphabet=2):
136 | def encode(bit):
137 | return encoding[bit]
138 | return gen_sub(freq, zerolen, onelen, 1, 0, ''.join(encode(b) for b in de_bruijn(alphabet, bitlen)))
139 |
140 |
141 | def gen_opensesame():
142 | # https://github.com/samyk/opensesame/blob/48b7d25c9d7aa3e2ac5cadfdcb2db1c78e001565/garages.h
143 | # 300000000, 310000000, 315000000, 318000000, 390000000, 433920000
144 |
145 | for hz in [300000000, 310000000]:
146 | with open(f'10bit-{hz//1000000}mhz.sub', 'w') as f:
147 | print(debruijn(hz, 500, 500, {'0': '1000', '1': '1110'}, 10), file=f)
148 |
149 | for hz in [315000000, 390000000]:
150 | with open(f'9bit-{hz//1000000}mhz.sub', 'w') as f:
151 | print(debruijn(hz, 500, 500, {'0': '1000', '1': '1110'}, 9), file=f)
152 |
153 | for hz in [318000000, 433920000]:
154 | with open(f'nscd-{hz//1000000}.sub', 'w') as f:
155 | print(debruijn(hz, 500, 500, {'0': '100000000100000000',
156 | '1': '111111110100000000',
157 | '2': '111111110111111110'}, 9, alphabet=3), file=f)
158 |
159 | for hz in [300000000, 310000000, 315000000, 318000000, 390000000, 433920000]:
160 | with open(f'12bit-{hz//1000000}mhz.sub', 'w') as f:
161 | print(debruijn(hz, 500, 500, {'0': '1000', '1': '1110'}, 12), file=f)
162 |
163 |
164 | # pylint: disable=line-too-long
165 | def gen_tesla():
166 | # https://github.com/jimilinuxguy/Tesla-Charging-Port-Opener
167 | with open('tesla.sub', 'w') as f:
168 | print(gen_sub(315000000, 400, 400, 10, 25562, '101010101010101010101010100010101100101100110010110011001100110011001011010011010010110101001010110100110100110010101011010010110001010110010110011001011001100110011001100101101001101001011010100101011010011010011001010101101001011000101011001011001100101100110011001100110010110100110100101101010010101101001101001100101010110100101'), file=f)
169 |
170 |
171 | # see Also https://github.com/merbanan/rtl_433/blob/master/conf/fan-11t.conf
172 |
173 | # 01 + 4 bit ID + 0 + 6 bit command
174 | fan_comm = {
175 | 'High': '100000',
176 | 'Med': '010000',
177 | 'Low': '001000',
178 | # '???': '000100', # not used ?
179 | 'Off': '000010',
180 | 'Lit': '000001',
181 | }
182 | fan_end = '000000'
183 | fan_freq = 302500000
184 |
185 | # DRATE 3015
186 | # (1/3015) * 1000000 = ~333us
187 | fan_bit_len = 333
188 |
189 |
190 | def gen_fan_cmd(pin="1010"):
191 | """
192 | FAN-11T Remote Control of Harbor Breeze Fan
193 | """
194 |
195 | # Fan used PWM, to transmit as OOK we pad out the 1's and 0's
196 | # PWM into OOK
197 | # 1 = 011
198 | # 0 = 001
199 | fan_comm_end = ''.join(['011' if b == '1' else '001' for b in f"01{pin}0{fan_end}"])
200 | fan_space = '0' * 39
201 |
202 | if _verbose:
203 | print('end', fan_end)
204 | print('fan_end cmd_pwm', fan_comm_end)
205 |
206 | for k, v in fan_comm.items():
207 |
208 | f_cmd = ''.join(['011' if b == '1' else '001' for b in f"01{pin}0{v}"])
209 |
210 | # freq, zerolen, onelen, repeats, pause, bits
211 | # cmd_pwm = f'{fan_space}{f_cmd}'
212 | # full_pwm = (cmd_pwm * 5 + fan_space + fan_comm_end + fan_space) * 2
213 | cmd_pwm = f'{f_cmd}{fan_space}'
214 | full_pwm = (cmd_pwm * 5 + fan_comm_end + fan_space) * 2
215 | # print('fan_{}.sub'.format(k), fan_comm[k])
216 | if _verbose:
217 | print(k, v)
218 | print(f'fan_{k} cmd_pwm', cmd_pwm)
219 | # print("xmit us:", len(full_pwm) * fan_bit_len)
220 | # print(f'fan_{k} full_pwm', full_pwm)
221 |
222 | with open(f'fan_{k}-{pin}.sub', 'w') as f:
223 | # gen_sub(freq, zerolen, onelen, repeats, pause, bits)
224 | print(gen_sub(fan_freq, fan_bit_len, fan_bit_len, 1, 0, full_pwm), file=f)
225 |
226 |
227 | def gen_fan_brute():
228 | """
229 | FAN-11T Remote Control of Harbor Breeze Fan
230 |
231 | Brute Force 4 bit pin code
232 | """
233 |
234 | fan_space = "0" * 39
235 |
236 | # Fan used PWM, to transmit as OOK we pad out the 1's and 0's
237 | # PWM into OOK
238 | # 1 = 011
239 | # 0 = 001
240 |
241 | # if _verbose:
242 | # print('end', fan_end)
243 | # print('fan_end cmd_pwm', fan_comm_end)
244 |
245 | for k, v in fan_comm.items():
246 |
247 | pwm_dat = []
248 |
249 | for p in range(16):
250 |
251 | pin = f"{p:04b}"
252 |
253 | f_cmd = ''.join(['011' if b == '1' else '001' for b in f"01{pin}0{v}"])
254 | fan_cmd_end = ''.join(['011' if b == '1' else '001' for b in f"01{pin}0{fan_end}"])
255 |
256 | cmd_pwm = f'{f_cmd}{fan_space}'
257 | full_pwm = (cmd_pwm * 4 + fan_cmd_end + fan_space) * 2
258 |
259 | pwm_dat.append(full_pwm)
260 |
261 | if _verbose:
262 | print(k, pin, v)
263 | print(f'fan_{k} cmd_pwm', cmd_pwm)
264 | # print(f'fan_{k} full_pwm', full_pwm)
265 |
266 | if _verbose:
267 | print(k, "xmit us:", len("".join(pwm_dat)) * fan_bit_len)
268 |
269 | with open(f'fan_brute-{k}.sub', 'w') as f:
270 | # gen_sub(freq, zerolen, onelen, repeats, pause, bits)
271 | print(gen_sub(fan_freq, fan_bit_len, fan_bit_len, 1, 0, "".join(pwm_dat), comment_text=f"FAN-11T Remote Control {k}"), file=f)
272 |
273 |
274 | TOUCH_TUNES_COMMANDS = {
275 | 'On_Off': 0x78,
276 | 'Pause': 0x32, # 0xB3,
277 | 'P1': 0x70, # 0xF1,
278 | 'P2_Edit_Queue': 0x60,
279 | 'P3_Skip': 0xCA,
280 | 'F1_Restart': 0x20,
281 | 'F2_Key': 0xA0,
282 | 'F3_Mic_A_Mute': 0x30,
283 | 'F4_Mic_B_Mute': 0xB0,
284 | 'Mic_Vol_Plus_Up_Arrow': 0xF2,
285 | 'Mic_Vol_Minus_Down_Arrow': 0x80,
286 | 'A_Left_Arrow': 0x84,
287 | 'B_Right_Arrow': 0xC4,
288 | 'OK': 0x44, # 0xDD,
289 | 'Music_Vol_Zone_1Up': 0xD0, # 0xF4,
290 | 'Music_Vol_Zone_1Down': 0x50,
291 | 'Music_Vol_Zone_2Up': 0x90, # 0xF6,
292 | 'Music_Vol_Zone_2Down': 0x10,
293 | 'Music_Vol_Zone_3Up': 0xC0, # 0xFC,
294 | 'Music_Vol_Zone_3Down': 0x40,
295 | '1': 0xF0,
296 | '2': 0x08,
297 | '3': 0x88,
298 | '4': 0x48,
299 | '5': 0xC8,
300 | '6': 0x28,
301 | '7': 0xA8,
302 | '8': 0x68,
303 | '9': 0xE8,
304 | '0': 0x98,
305 | 'Music_Karaoke(star)': 0x18,
306 | 'Lock_Queue(#)': 0x58
307 | }
308 |
309 |
310 | def encode_touchtunes(command, pin=0x00):
311 | # Syncword
312 | frame = 0x5D
313 |
314 | # PIN
315 | for bit in range(8):
316 | frame <<= 1
317 | if pin & (1 << bit):
318 | frame |= 1
319 | # Insert button code and it's complement
320 | frame <<= 16
321 | frame |= (command << 8)
322 | frame |= (command ^ 0xFF)
323 |
324 | # Convert to raw signal
325 | # 0 symble == 10 && 1 symble == 1000
326 | ook = ""
327 | for _i in range(8 + 8 + 16):
328 | if frame & 0x80000000:
329 | ook += "1000"
330 | frame <<= 1
331 | else:
332 | ook += "10"
333 | frame <<= 1
334 | return "1" * 16 + "0" * 8 + ook + "1000"
335 |
336 |
337 | # Touch Tunes jukebox (https://github.com/notpike/The-Fonz/blob/master/The_Fonz.py)
338 | def gen_touch_tunes(pin=0):
339 | # pin 0->255
340 |
341 | dirname = f"touch_tunes-{pin:03d}"
342 | if not os.path.isdir(dirname):
343 | os.mkdir(dirname)
344 |
345 | # Touch Tunes jukebox (https://github.com/notpike/The-Fonz/blob/master/The_Fonz.py)
346 | for cmdname, cmd in TOUCH_TUNES_COMMANDS.items():
347 | with open(dirname + '/' + cmdname + '.sub', 'w') as f:
348 | print(gen_sub(433920000, 566, 566, 1, 0, encode_touchtunes(cmd, pin)), file=f)
349 |
350 |
351 | if __name__ == '__main__':
352 |
353 | targ = "all"
354 | args = sys.argv[1:]
355 |
356 | if args:
357 | targ = args.pop(0)
358 |
359 | # Garage Door opener
360 | if targ in ["all", "opensesame"]:
361 | gen_opensesame()
362 |
363 | # Tesla-Charging-Port-Opener
364 | if targ in ["all", "tesla"]:
365 | gen_tesla()
366 |
367 | # Touch Tunes jukebox
368 | if targ in ["all", "ttones"]:
369 | gen_touch_tunes()
370 |
371 | # FAN-11T Remote Control of Harbor Breeze Fan ( with pin )
372 | # gen_fan_cmd("1010")
373 |
374 | # FAN-11T Remote Control of Harbor Breeze Fan
375 | # Brute Force Pin
376 | if targ in ["all", "fan"]:
377 | gen_fan_brute()
378 |
379 | sys.exit()
380 |
--------------------------------------------------------------------------------
/subghz_gen_cmd.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | #
4 | # A command line bases generator for Flipper SubGhz RAW File
5 | #
6 | # Peter Shipley github.com/evilpete
7 | #
8 | # From pkg https://github.com/evilpete/flipper_toolbox
9 | #
10 | # Based heavily on jinschoi/create_sub.py
11 | #
12 | # https://gist.github.com/jinschoi/f39dbd82e4e3d99d32ab6a9b8dfc2f55
13 | #
14 | #
15 |
16 | import sys
17 | import time
18 | # import os
19 | # from typing import Iterable, Union, Any
20 | import argparse
21 |
22 | # pylint: disable=unspecified-encoding, too-many-arguments, too-many-locals, unused-argument
23 |
24 | _verbose = 0
25 |
26 | # Preset: FuriHalSubGhzPreset2FSKDev238Async
27 | # Preset: FuriHalSubGhzPreset2FSKDev476Async
28 | # Preset: FuriHalSubGhzPresetOok270Async
29 | # Preset: FuriHalSubGhzPresetOok650Async
30 | # listed in Firmware but not avalible (yet)
31 | # FuriHalSubGhzPresetMSK99_97KbAsync
32 | # FuriHalSubGhzPresetGFSK9_99KbAsync
33 |
34 |
35 | def gen_sub(freq, zerolen, onelen, baudrate=None, pause=0, bits="", modu='Ook', modopt=650):
36 | """generate Flipper SubGhz RAW data
37 |
38 | Parameters
39 | ----------
40 | int : freq
41 | frequency in Hz
42 | int : zerolen
43 | length of space bit in us
44 | int ; onelen
45 | length of mark bit in us
46 | int : baud
47 | baud rate, is given options zerolen and onelen are ignored
48 | int : repeats
49 | number of times to repeat sequence
50 | int : pause
51 | time to wait in us between sequence, defaults to value zerolen
52 | str : bits
53 | string of ones and zeros to represent sequence
54 | str : modu
55 | modulation, valid values 2FSK or Ook, default="Ook"
56 | str : modopt
57 | modulation option, valid values:
58 | Ook: '270' or '650'
59 | 2FSK: Dev238' or 'Dev476
60 |
61 | Returns
62 | -------
63 | str
64 | binary data in string form
65 |
66 | """
67 |
68 | res = f"""Filetype: Flipper SubGhz RAW File
69 | Version: 1
70 | Frequency: {freq}
71 | # {time.ctime()}
72 | # Generated with https://github.com/evilpete/flipper_toolbox
73 | Preset: FuriHalSubGhzPreset{modu}{modopt}Async
74 | Protocol: RAW
75 | """
76 |
77 | if baudrate is not None:
78 | zerolen = onelen = (1 / baudrate) * 1000000
79 |
80 | # if modu not in ['Ook', "2FSK"]:
81 | # raise ValueError("modu value can only be 'Ook' or '2FSK'")
82 | #
83 | # if modu == 'Ook' and modopt not in ['270', '650']:
84 | # raise ValueError("Ook: modopt value can only be '270' or '650'")
85 | #
86 | # if modu == '2FSK' and modopt not in ['Dev238', 'Dev476']:
87 | # raise ValueError("2FSK: modopt value can only be 'Dev238' or 'Dev476'")
88 |
89 | zerolen_off = zerolen % 1
90 | onelen_off = onelen % 1
91 | delta_off = 0.0
92 |
93 | zerolen = int(zerolen)
94 | onelen = int(onelen)
95 |
96 | # if _verbose:
97 | # print( f"zerolen={zerolen}, onelen={onelen}, baudrate={baudrate}, "
98 | # f"zerolen_off={zerolen_off:0.04f}, onelen_off={onelen_off:0.03f}" )
99 |
100 | if pause == 0:
101 | # Pause must be non-zero.
102 | pause = zerolen
103 |
104 | data = []
105 | prevbit = None
106 | prevbitlen = 0
107 | for bit in bits:
108 | if prevbit and prevbit != bit:
109 | data.append(prevbitlen)
110 | prevbitlen = 0
111 |
112 | if bit == '1':
113 | delta_off += onelen_off
114 | prevbitlen += onelen
115 | if delta_off > 1:
116 | prevbitlen += 1
117 | delta_off -= 1
118 | else:
119 | delta_off += zerolen_off
120 | prevbitlen -= zerolen
121 | if delta_off > 1:
122 | prevbitlen -= 1
123 | delta_off -= 1
124 |
125 | prevbit = bit
126 |
127 | if prevbit == '1':
128 | data.append(prevbitlen)
129 | data.append(-pause)
130 | else:
131 | data.append(prevbitlen - pause)
132 |
133 | # data = (data * repeats)[:-1] # Drop the last pause.
134 | datalines = []
135 | for i in range(0, len(data), 512):
136 | batch = [str(n) for n in data[i:i + 512]]
137 | datalines.append(f'RAW_Data: {" ".join(batch)}')
138 |
139 | res += '\n'.join(datalines)
140 |
141 | if _verbose > 1:
142 | print(f"delta_off {delta_off}")
143 |
144 | return res
145 |
146 |
147 | def hex2bin(s):
148 | """Convert strings of Hedecimal data into binary strings
149 |
150 | Parameters
151 | ----------
152 | str
153 | hexadecimal data in string form
154 |
155 | Returns
156 | -------
157 | str
158 | binary data in string form
159 |
160 | """
161 |
162 | r = []
163 | if s[:2] in ["0x", "OX"]:
164 | s = s[2:]
165 | sl = len(s)
166 | # if (sl % 2):
167 | # s += '0'
168 | for i in range(0, sl, 1):
169 | b = "{:04b}".format(int(s[i], 16)) # pylint: disable=consider-using-f-string
170 | # print(s[i], b)
171 | r.append(b)
172 | return ''.join(r)
173 |
174 |
175 | Modulation_Presets = {
176 | '2FSKDev238': ('2FSK', 'Dev238'), # FuriHalSubGhzPreset2FSKDev238Async
177 | '2FSKDev476': ('2FSK', 'Dev476'), # FuriHalSubGhzPreset2FSKDev476Async
178 | 'Ook270': ('Ook', '270'), # FuriHalSubGhzPresetOok270Async
179 | 'Ook650': ('Ook', '650'), # FuriHalSubGhzPresetOok650Async
180 | }
181 |
182 |
183 | def arg_line():
184 | """ Parse command line args.
185 |
186 | Parameters
187 | ----------
188 | None
189 |
190 | Returns
191 | -------
192 | argparse Namespace obj
193 |
194 | """
195 | # pylint: disable=global-statement
196 | global _verbose
197 |
198 | epilog = f'''
199 | example:\n\t {sys.argv[0]} -f 302500000 -0 333 -1 333 -m -B 0110100001000
200 | \n\t {sys.argv[0]} -f 302500000 -b 3015 -m -H 0x6840 -p Ook650
201 |
202 | If baud is given options zerolen and onelen are ignored
203 |
204 | Modulation presets:
205 | 2FSKDev238: FuriHalSubGhzPreset2FSKDev238Async
206 | 2FSKDev476: FuriHalSubGhzPreset2FSKDev476Async
207 | Ook270: FuriHalSubGhzPresetOok270Async
208 | Ook650: FuriHalSubGhzPresetOok650Async
209 | '''
210 |
211 | parser = argparse.ArgumentParser(add_help=True, # noqa
212 | epilog=epilog,
213 | formatter_class=argparse.RawDescriptionHelpFormatter
214 | )
215 |
216 | parser.add_argument('-v', '--verbose', dest="verb",
217 | default=0,
218 | help='Increase debug verbosity', action='count')
219 |
220 | parser.add_argument("-o", "--outfile", dest="out_file",
221 | default="subghz.sub",
222 | help="Output filename")
223 |
224 | parser.add_argument("-f", "--freq", dest="send_freq",
225 | type=int,
226 | default=433920000,
227 | help="Transmit frequency")
228 |
229 | parser.add_argument("-0", "--zerolen", dest="zero_len",
230 | type=int,
231 | default=None,
232 | help="Length of space bit in ms")
233 |
234 | parser.add_argument("-1", "--onelen", dest="one_len",
235 | type=int,
236 | default=None,
237 | help="Length of mark bit in ms")
238 |
239 | parser.add_argument("-i", "--invert", dest="invert",
240 | action='store_true',
241 | help="Invert bits")
242 |
243 | parser.add_argument("-b", "--baud", dest="baud_rate",
244 | type=int,
245 | default=None,
246 | help="data baud rate")
247 |
248 | data_grp = parser.add_mutually_exclusive_group(required=True)
249 |
250 | data_grp.add_argument("-H", "--Hex", dest="hex_data",
251 | default=None,
252 | help="Packet data in hex")
253 |
254 | data_grp.add_argument("-B", "--Binary", dest="bin_data",
255 | default='None',
256 | help="Packet data as string of ones and zeros")
257 |
258 | # Preset: FuriHalSubGhzPreset2FSKDev238Async
259 | # Preset: FuriHalSubGhzPreset2FSKDev476Async
260 | # Preset: FuriHalSubGhzPresetOok270Async
261 | # Preset: FuriHalSubGhzPresetOok650Async
262 | parser.add_argument("-p", "--preset", dest="mod_preset",
263 | default='Ook650',
264 | help="Modulation preset")
265 |
266 | parser.add_argument("-m", "--manchester", dest="manch_encode",
267 | action='store_true',
268 | help="manchester encoded")
269 |
270 | parser.add_argument("-r", "--repeat", dest="repeat_cnt",
271 | type=int, default=1,
272 | help="number of times to repeat sequence")
273 |
274 | parser.add_argument("-d", "--delay", dest="delay_padding",
275 | type=int, default=1,
276 | help="delay padding between repeated sequences")
277 |
278 | args_data, _unknown_args = parser.parse_known_args()
279 |
280 | if args_data.verb:
281 | _verbose += args_data.verb
282 |
283 | if _verbose:
284 | print(f"\nargs: {args_data}\n")
285 |
286 | return args_data
287 |
288 |
289 | def main():
290 |
291 | args = arg_line()
292 | zero_len = one_len = None
293 |
294 | if args.baud_rate is None:
295 | if args.zero_len and args.one_len:
296 | zero_len = args.zero_len
297 | one_len = args.one_len
298 | elif args.zero_len or args.one_len:
299 | zero_len = one_len = args.zero_len or args.one_len
300 | else:
301 | print("Error: Bit Length or Baudrate must be given")
302 | print("\tuse --help opton for more info\n")
303 | # parser.print_help()
304 | sys.exit(1)
305 |
306 | mod_settings = ('Ook', '650')
307 | if args.mod_preset in Modulation_Presets:
308 | mod_settings = Modulation_Presets[args.mod_preset]
309 |
310 | if args.hex_data:
311 | bin_data = hex2bin(args.hex_data)
312 | if _verbose:
313 | print(f"hex_data: {args.hex_data}")
314 | else:
315 | bin_data = args.bin_data
316 |
317 | # print(f"bin_data: {bin_data}")
318 |
319 | if args.manch_encode:
320 | bin_data = ''.join(['10' if b == '1' else '01' for b in bin_data])
321 |
322 | if args.invert:
323 | bin_data = ''.join(['0' if b == '1' else '1' for b in bin_data])
324 |
325 | if _verbose:
326 | print(f"bin_data: {bin_data}")
327 |
328 | packet_data = gen_sub(args.send_freq,
329 | zero_len, one_len, args.baud_rate, 0,
330 | bin_data,
331 | mod_settings[0], mod_settings[1])
332 |
333 | if _verbose > 1:
334 | print(f"packet_data: {packet_data}")
335 |
336 | with open(args.out_file, 'w', encoding="utf-8") as fd:
337 | print(packet_data, file=fd)
338 |
339 | sys.exit()
340 |
341 |
342 | if __name__ == '__main__':
343 | main()
344 |
--------------------------------------------------------------------------------
/subghz_histogram.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | Peter Shipley github.com/evilpete
4 |
5 | Script to read Flipper SubGhz RAW File and plot 0 & 1 segment lengths using pyplot
6 |
7 | From pkg https://github.com/evilpete/flipper_toolbox
8 |
9 | Based heavily on jinscho's gist :
10 | https://gist.github.com/jinschoi/8396f25a4cb7ac7986a7d881026ae950
11 | """
12 |
13 | import re
14 | import sys
15 | from statistics import mean, median_high
16 | import pandas as pd
17 | import matplotlib.pyplot as plt
18 |
19 | # LIMIT = 1000 # this number is arbitrary
20 | LIMIT = None # If None, limit will be calculated from the median
21 |
22 | _debug = 0
23 |
24 | filename = sys.argv[1]
25 |
26 | psegs = []
27 | nsegs = []
28 | with open(filename, 'r', encoding="utf-8") as fd:
29 | header = fd.readline().strip()
30 | if header != 'Filetype: Flipper SubGhz RAW File':
31 | print(f"Error: {filename} is not a 'Flipper SubGhz RAW File' sample file'")
32 | sys.exit(1)
33 |
34 | for line in fd:
35 | m = re.match(r'RAW_Data:\s*([-0-9 ]+)\s*$', line)
36 | if m:
37 | nsegs.extend(abs(int(seg)) for seg in m[1].split(r' ') if int(seg) < 0)
38 | psegs.extend(abs(int(seg)) for seg in m[1].split(r' ') if int(seg) > 0)
39 |
40 | if _debug:
41 | print("nseg :", min(nsegs), mean(nsegs), max(nsegs))
42 | print("pseg :", min(psegs), mean(psegs), max(psegs))
43 |
44 |
45 | limit = LIMIT
46 | if limit is None:
47 | data_median = max(median_high(nsegs), median_high(psegs))
48 | limit = 4 * data_median
49 | print(f"Limit = median * 4 = {data_median} * 4 = {limit}")
50 | # max_dat = max(nsegs + psegs)
51 | # print("max =", max_dat)
52 |
53 |
54 | pseries = pd.Series(data=psegs)
55 | nseries = pd.Series(data=nsegs)
56 |
57 | pseries = pseries[pseries < limit]
58 | nseries = nseries[nseries < limit]
59 |
60 | df = pd.DataFrame(pseries, columns=['pos'])
61 | df['neg'] = nseries
62 |
63 | ax = df.plot.hist(bins=int(limit / 4),
64 | log=False,
65 | alpha=0.5, figsize=(6, 3),
66 | title='Histogram of segment length')
67 |
68 | ax.set(xlabel='milliseconds')
69 |
70 | ax.grid(True, which='major', axis='y')
71 |
72 | plt.show()
73 |
--------------------------------------------------------------------------------
/subghz_insteon.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | subghz_insteon.py : Generate Insteon command packets in Flipper .sub format
4 |
5 | Written By: Peter Shipley github.com/evilpete
6 |
7 | From pkg https://github.com/evilpete/flipper_toolbox
8 | """
9 |
10 | import sys
11 | import time
12 | # import argparse
13 | # import string
14 | # import pprint
15 |
16 | #
17 | # Generate Insteon command packets in Flipper .sub format
18 | #
19 | # Peter Shipley github.com/evilpete
20 | #
21 | # From pkg https://github.com/evilpete/flipper_toolbox
22 | #
23 |
24 | # Usage;
25 | # ./subghz_insteon.py [On|Off]
26 | #
27 | # Example:
28 | # ./subghz_insteon.py 163FE5 132580 Off > device_off.sub
29 | #
30 |
31 |
32 | # Note:
33 | #
34 | # an insteon switch needs to be "paired" before it will accept command from
35 | # andother device, but there is no authenticaion or encryption.
36 | #
37 | # the easiest way to get the insteon node id/address of a pair is to run rtl_433
38 | #
39 | # rtl_433 -f 914.8M -s 2048k -R 159 -Y classic
40 | #
41 | # rtl_433 output:
42 | # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
43 | # time : 2022-11-28 21:36:45
44 | # model : Insteon From_Addr : 4C1B63 To_Addr : 347864 Message_Type: 0
45 | # Message_Str: Direct Message Extended : 0 Hops_Max : 3
46 | # Hops_Left : 0 Packet : 03 : 247864 : 4C1B61 : 13 00 BE Integrity : CRC
47 | # Payload : 03647824611B4C1300BE00
48 |
49 | # the run the command :
50 | #
51 | # ./subghz_insteon.py 4C1B63 347864 Off > office_light_off.sub
52 | #
53 |
54 | # Insteon Packet encoding format :
55 | #
56 | # Packet encoding example
57 | #
58 | # The short Packet Fields are
59 | # Flags = byte 0
60 | # To Addr = byte 1 2 3
61 | # From Addr = byte 4 5 6
62 | # Command = byte 7
63 | # Cmd Arg = byte 8
64 | # Pkt CRC = byte 9
65 | # pad 00 = byte 10 11 ( optional )
66 | # pad AA = byte 12 ( optional )
67 | #
68 |
69 | _debug = 0
70 |
71 | lsfr_table = [0x00, 0x30, 0x60, 0x50, # 0 1 2 3
72 | 0xC0, 0xF0, 0xA0, 0x90, # 4 5 6 7
73 | 0x80, 0xB0, 0xE0, 0xD0, # 8 9 A B
74 | 0x40, 0x70, 0x20, 0x10] # C D E F
75 |
76 | cmd_table = {
77 | "ON": (0x11, 255),
78 | "FASTON": (0x12, None),
79 | "OFF": (0x13, None),
80 | "FASTOFF": (0x14, None),
81 | 'BRIGHTEN': (0x15, None),
82 | "BRT": (0x15, None),
83 | "DIM": (0x16, None),
84 | "FADEDOWN": (0x17, 0),
85 | "FADEUP": (0x17, 1),
86 | "STOP": (0x18, 0),
87 | "FADESTOP": (0x18, 0),
88 | "BEEP": (0x30, None),
89 | "PING": (0x0F, None),
90 | }
91 |
92 |
93 | def pkt_crc(dat):
94 | """
95 | calc packet CRC
96 |
97 | takes an instion packet in form of a list of ints
98 | and returns the CRC for RF packet
99 |
100 | This uses a table lookup to effectivly doing:
101 | r ^= dat[i] ;
102 | r ^= (( r ^ ( r << 1 )) & 0x0F) << 4 ;
103 |
104 | """
105 |
106 | r = 0
107 | for i in dat[:9]:
108 | r ^= i
109 | r ^= lsfr_table[r & 0x0F]
110 |
111 | return r
112 |
113 |
114 | def percent_to_byte(p_str, def_val=255):
115 | if p_str.isdigit():
116 | p = int(p_str)
117 | r = int(p * 255 / 100)
118 | return min(r, 255)
119 |
120 | return def_val
121 |
122 |
123 | # takes a list representig a insteon rf command bytes / payload
124 | # and generates a rf binary in the form of a string
125 | def insteon_encode(b_list, repeat=3):
126 | # l = len(b_list)
127 |
128 | padding = ''.join(['10' if b == '1' else '01' for b in "0101" * 13])
129 |
130 | aa = ''.join(['10' if b == '1' else '01' for b in "01010101"])
131 | blks = [aa]
132 | i = 0
133 | for x in b_list:
134 | if i == 0:
135 | ix = 31
136 | else:
137 | ix = 12 - i
138 | i += 1
139 |
140 | d = x
141 |
142 | ibr = f"{ix:05b}"[::-1]
143 | dbr = f"{d:08b}"[::-1]
144 |
145 | if _debug > 1:
146 | print("00", ibr, dbr, " : ", ix, f"{x:02X}", file=sys.stderr)
147 |
148 | # ib = f"{ix:05b}"
149 | # db = f"{d:08b}"
150 | # print(ix, cmd_hex[x:x+2], ib, db, '->', ibr, dbr)
151 |
152 | md = ''.join(['10' if b == '1' else '01' for b in f"{ibr}{dbr}"])
153 | if _debug > 1:
154 | print("md=", md, file=sys.stderr)
155 | blks.append('00' + md)
156 |
157 | inst_pkt = ''.join(blks)
158 |
159 | ret_list = [inst_pkt]
160 |
161 | for i in range(1, repeat):
162 | ret_list.extend((padding, inst_pkt))
163 |
164 | # print(ret_list)
165 | return ret_list
166 |
167 |
168 | hex_set = set('abcdefABCDEF0123456789')
169 |
170 |
171 | def is_hex_str(s):
172 | return set(s).issubset(hex_set)
173 |
174 |
175 | # takes a list representig a insteon rf command bytes
176 | def gen_insteon_pkt():
177 |
178 | pkt_list = [0x0F]
179 |
180 | args = sys.argv[1:]
181 |
182 | if _debug > 1:
183 | print("args", args, file=sys.stderr)
184 |
185 | if len(args) < 3:
186 | print("requires three or more args")
187 | sys.exit()
188 |
189 | # dest addr
190 | addr = args.pop(0)
191 |
192 | a = [addr[4:6], addr[2:4], addr[0:2]]
193 | # pkt_list.extend([int(x, 16) for x in a])
194 | pkt_list.extend(map(lambda x: int(x, 16), a))
195 |
196 | # src addr
197 | addr = args.pop(0)
198 |
199 | if addr.startswith('0000'):
200 | pkt_list[0] = 0xCF
201 |
202 | a = [addr[4:6], addr[2:4], addr[0:2]]
203 | pkt_list.extend(map(lambda x: int(x, 16), a))
204 | # pkt_list.extend([int(x, 16) for x in a])
205 |
206 | cmd = args.pop(0)
207 | cmd_arg = None
208 |
209 | if cmd.upper() in cmd_table:
210 | c1, cmd_arg = cmd_table[cmd.upper()]
211 | pkt_list.append(c1)
212 | elif is_hex_str(cmd):
213 | pkt_list.append(int(cmd, 16) & 0xff)
214 | else:
215 | print(f"unknown cmd value '{cmd}'")
216 | print("valid commands are:'")
217 | print("\t", " ".join(cmd_table.keys()))
218 | sys.exit()
219 |
220 | if args:
221 | arg = args.pop(0)
222 | if is_hex_str(arg):
223 | val = int(arg, 16)
224 | pkt_list.append(val)
225 | # val = percent_to_byte(arg[1:])
226 | else:
227 | print(f"unknown arg value '{arg}'")
228 | sys.exit()
229 | elif cmd_arg is not None:
230 | pkt_list.append(cmd_arg)
231 | else:
232 | pkt_list.append(0)
233 |
234 | p_crc = pkt_crc(pkt_list)
235 |
236 | pkt_list.extend([p_crc, 0, 0, 0xAA])
237 |
238 | if _debug > 1:
239 | print("pkt_list", pkt_list, file=sys.stderr)
240 | # hex_str_list = [f"{x:02X}" for x in pkt_list]
241 | hex_str_list = list(map(lambda x: f"{x:02X}", pkt_list))
242 | print(hex_str_list, file=sys.stderr)
243 | print("".join(hex_str_list), file=sys.stderr)
244 |
245 | return pkt_list
246 |
247 |
248 | # takes a rf binary in the form of a string
249 | # and generates a Flipper SubGhz encoded file
250 | def print_subfile(pkt_list, note="Insteon Command"):
251 |
252 | pkt_bit_len = 109.2
253 |
254 | bit_len = int(pkt_bit_len)
255 | bit_len_off = pkt_bit_len % 1
256 | delta_off = 0.0
257 |
258 | data_list = []
259 | for pkt_bits in pkt_list:
260 |
261 | data = []
262 | prevbit = None
263 | prevbitlen = 0
264 |
265 | for bit in pkt_bits:
266 | if prevbit and prevbit != bit:
267 | data.append(prevbitlen)
268 | prevbitlen = 0
269 |
270 | if bit == '1':
271 | delta_off += bit_len_off
272 | prevbitlen += bit_len
273 | if delta_off > 1:
274 | prevbitlen += 1
275 | delta_off -= 1
276 | else:
277 | delta_off += bit_len_off
278 | prevbitlen -= bit_len
279 | if delta_off > 1:
280 | prevbitlen -= 1
281 | delta_off -= 1
282 |
283 | prevbit = bit
284 |
285 | data.append(prevbitlen)
286 |
287 | data_list.append(data)
288 |
289 | hdr = f"""Filetype: Flipper SubGhz RAW File
290 | Version: 1
291 | # {note}
292 | # Generated with subghz_insteon.py https://github.com/evilpete/flipper_toolbox
293 | # {time.ctime()}
294 | Frequency: 915000000
295 | Preset: FuriHalSubGhzPreset2FSKDev476Async
296 | Protocol: RAW
297 | """
298 |
299 | res = hdr
300 | datalines = []
301 | for data in data_list:
302 | for i in range(0, len(data), 512):
303 | # batch = [str(n) for n in data[i:i + 512]]
304 | batch = map(str, data[i:i + 512])
305 | datalines.append(f'RAW_Data: {" ".join(batch)}')
306 |
307 | res += '\n'.join(datalines)
308 |
309 | return res
310 |
311 |
312 | if __name__ == '__main__':
313 |
314 | p_list = gen_insteon_pkt()
315 |
316 | hexstr = ' '.join([f"{x:02X}" for x in p_list])
317 |
318 | if _debug:
319 | print("p_list", p_list, file=sys.stderr)
320 | # print([f"{x:02X}" for x in p_list], file=sys.stderr)
321 | print(hexstr, file=sys.stderr)
322 |
323 | pkt_data = insteon_encode(p_list)
324 |
325 | if _debug > 1:
326 | print("pkt_data", pkt_data, file=sys.stderr)
327 |
328 | file_comment = "Insteon command : " + \
329 | ' '.join(sys.argv[1:]).upper() + " : " + hexstr
330 |
331 | fdata = print_subfile(pkt_data, note=file_comment)
332 |
333 | print(fdata)
334 |
335 | sys.exit()
336 |
--------------------------------------------------------------------------------
/subghz_ook_to_sub.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | #
4 | # Peter Shipley github.com/evilpete
5 | #
6 | # From pkg https://github.com/evilpete/flipper_toolbox
7 | #
8 | # convert .ook files produced by rtl_433 to the Flipper .sub format
9 |
10 | #
11 | # Usage:
12 | # subghz_ook_to_sub.py FILENAME [freq]")
13 | #
14 | # default freq 433920000 [433.92Mhz]
15 | #
16 | #
17 |
18 |
19 | # to convert unsigned 8-bit sdr data do the following:
20 | #
21 | # convert rtl-sdr raw data file into .ook file with rtl_sdr
22 | # (this will partially demodulate the data)
23 | #
24 | # rtl_443 -r rtl_sample.cu8 -w rf_sample.ook
25 | #
26 | # convert the .ook file into a Flipper .sub file
27 | #
28 | # subghz_ook_to_sub.py rf_sample.ook
29 | #
30 | # this will generate the file rf_sample.sub
31 | #
32 | # Note: you may have to manually set the frequancy on the
33 | # command line or by editing the file
34 |
35 | #
36 | # With multiple packets per ook file:
37 | # currently only reads first header and assumes all
38 | # following packets use same modulation
39 |
40 |
41 | # To do:
42 | # parse header
43 | # split samples into multiple files (opton)
44 | # data validation
45 | # .fsk file format ?
46 | # insert breaks between pkts
47 |
48 |
49 | import sys
50 | import os
51 | import time
52 | import pprint
53 | import argparse
54 |
55 | MIN_PULSES = 25
56 |
57 | filen = None
58 | rf_freq = 0
59 |
60 |
61 | rf_freq_default = 433920000
62 |
63 | verbose = 0
64 |
65 | _debug = 0
66 |
67 | # ;pulse data
68 | # ;version 1
69 | # ;timescale 1us
70 | # ;created 2022-11-14 13:59:15-0800
71 | # ;ook 21 pulses
72 | # ;freq1 -75324
73 | # ;centerfreq 0 Hz
74 | # ;samplerate 250000 Hz
75 | # ;sampledepth 8 bits
76 | # ;range 42.1 dB
77 | # ;rssi -0.1 dB
78 | # ;snr 8.0 dB
79 | # ;noise -8.1 dB
80 | # 532 1492
81 |
82 |
83 | def arg_opts():
84 |
85 | parser = argparse.ArgumentParser(add_help=True, allow_abbrev=True, # noqa
86 | description="Convert rtl_443 .ook format files into .sub format", # noqa
87 | formatter_class=argparse.RawDescriptionHelpFormatter
88 | )
89 | # argument_default=argparse.SUPPRESS,
90 |
91 | parser.add_argument("-m", "-min", metavar='pulses', dest="min_pulses",
92 | default=None,
93 | help="minimum number of signal pulses")
94 |
95 | parser.add_argument('-v', '--verbose', dest="verb",
96 | default=0,
97 | help='Increase debug verbosity', action='count')
98 |
99 | parser.add_argument("-f", "--freq", metavar='frequency', dest="freq",
100 | default=None,
101 | help="use frequency instead")
102 |
103 | parser.add_argument("-F", "--Freq", metavar='frequency',
104 | dest="default_freq",
105 | default=None,
106 | help=f"default frequency: {rf_freq_default}")
107 |
108 | parser.add_argument("-o", "--out", metavar='output_filename',
109 | dest="outfname",
110 | default=None,
111 | help="output filename")
112 |
113 | # parser.add_argument("-p", "--preface", metavar='preface_duration',
114 | # dest="preface_time",
115 | # default=None,
116 | # type=int,
117 | # help="insert a preface signal (in μs)")
118 |
119 | parser.add_argument("input_file", metavar='input-file', nargs='?',
120 | default=None,
121 | help="file file in .ook format")
122 |
123 | ar, gs = parser.parse_known_args()
124 |
125 | return ar, gs
126 |
127 |
128 | def chunks(lst, n=500):
129 | """Yield successive 500-sized chunks from lst."""
130 | for i in range(0, len(lst), n):
131 | yield lst[i:i + n]
132 |
133 |
134 | RF_PRESETS = {
135 | 'ook': "FuriHalSubGhzPresetOok650Async",
136 | 'fsk': "FuriHalSubGhzPreset2FSKDev476Async",
137 | }
138 | # Preset: FuriHalSubGhzPreset2FSKDev238Async
139 | # Preset: FuriHalSubGhzPreset2FSKDev476Async
140 | # Preset: FuriHalSubGhzPresetOok270Async
141 | # Preset: FuriHalSubGhzPresetOok650Async
142 |
143 |
144 | def gen_sub(freq, rf_samples):
145 |
146 | if _debug:
147 | print("\n\n\nrf_samples", rf_samples)
148 |
149 | dat = rf_samples[0].get('header')
150 |
151 | if _debug:
152 | print(f"header {dat}")
153 |
154 | comment_text = "generated with https://github.com/evilpete/flipper_toolbox/ook_to_sub.py"
155 |
156 | rf_Preset = None
157 | # Preset: FuriHalSubGhzPreset2FSKDev238Async
158 | # Preset: FuriHalSubGhzPreset2FSKDev476Async
159 | # Preset: FuriHalSubGhzPresetOok270Async
160 | # Preset: FuriHalSubGhzPresetOok650Async
161 |
162 | rf_Preset = RF_PRESETS.get(dat['modulation'], None)
163 |
164 | if rf_Preset is None:
165 | print("Can't determine modulation type from header")
166 | print(dat)
167 | sys.exit(1)
168 |
169 | try:
170 | if rf_freq:
171 | freq = rf_freq
172 | else:
173 | fhz = dat.get('centerfreq', '0 Hz').split()[0]
174 | fhz = int(fhz)
175 | if fhz:
176 | freq = fhz
177 | else:
178 | freq = rf_freq_default
179 | print(f"Using default frequency {rf_freq_default}")
180 | except ValueError:
181 | freq = rf_freq_default
182 |
183 | res = f"""Filetype: Flipper SubGhz RAW File
184 | Version: 1
185 | # {comment_text}
186 | # {time.ctime()}
187 | Frequency: {freq}
188 | Preset: {rf_Preset}
189 | Protocol: RAW
190 | """
191 |
192 | data = []
193 | raw_data = []
194 |
195 | # if args.preface_time:
196 | # raw_data.append(str(args.preface_time * -1))
197 |
198 | for ds in rf_samples:
199 | data = []
200 | dat = ds.get('data', [])
201 |
202 | for d in dat:
203 | a = list(map(int, d.split()))
204 | a[1] *= -1
205 | if a[0] == 0:
206 | del a[0]
207 | elif a[1] == 0:
208 | del a[1]
209 | data += a
210 |
211 | data = list(map(str, data))
212 |
213 | for i in chunks(data):
214 | raw_data.append(f'RAW_Data: {" ".join(i)}')
215 |
216 | res += '\n'.join(raw_data)
217 |
218 | return res
219 |
220 |
221 | def skip_to_next(ffd, symb=";end"):
222 | for line in ffd:
223 | if line.startswith(symb):
224 | return
225 |
226 |
227 | def main():
228 |
229 | # file_header = {}
230 |
231 | ook_Headers = [";pulse data"]
232 | # samp_mod = ""
233 | # samp_freq1 = 0
234 | # samp_freq2 = 0
235 |
236 | pulse_samples = []
237 | dat_sample = None
238 |
239 | if _debug:
240 | print(f"open {filen}")
241 |
242 | with open(filen, 'r', encoding="utf-8") as fd:
243 |
244 | header = fd.readline().strip()
245 | if header not in ook_Headers:
246 | print(f"Error: {filen} is not a 'rtl_443 ook' data file")
247 | sys.exit(1)
248 |
249 | for line in fd:
250 |
251 | if line.startswith(';end'):
252 | if _debug:
253 | print("\n\ndat_sample", dat_sample)
254 | print("pulse_samples", pulse_samples)
255 |
256 | if verbose:
257 | print(f"Adding packet with {file_header['pulses']} pulses")
258 |
259 | dat_sample = None
260 | continue
261 |
262 | if dat_sample is None:
263 | dat_sample = {}
264 | dat_sample['header'] = file_header = {}
265 | dat_sample['data'] = pulse_data = []
266 | pulse_samples.append(dat_sample)
267 |
268 | if line.startswith(';ook') or line.startswith(';fsk'):
269 | a = line[1:].strip().split(None, 2)
270 | if a[1].isnumeric():
271 | if int(a[1]) < MIN_PULSES:
272 | if verbose:
273 | print(f"skipping packet with {a[1]} pulses")
274 | skip_to_next(fd)
275 | continue
276 |
277 | file_header['pulses'] = int(a[1])
278 | file_header['modulation'] = a[0]
279 |
280 | if line[0] == ';':
281 | a = line[1:].strip().split(None, 1)
282 | file_header[a[0]] = a[1]
283 | continue
284 |
285 | pulse_data.append(line.strip())
286 |
287 | print("Total packets in file", len(pulse_samples))
288 |
289 | sub_data = gen_sub(rf_freq, pulse_samples)
290 |
291 | if _debug or verbose > 2:
292 | # print(f"\n\n{pulse_samples}\n")
293 | pprint.pprint(pulse_samples)
294 |
295 | if args.outfname:
296 | outfilen = args.outfname
297 | if not outfilen.endswith('.sub'):
298 | outfilen += '.sub'
299 | else:
300 | outfilen = os.path.splitext(filen)[0] + ".sub"
301 |
302 | with open(outfilen, 'w', encoding="utf-8") as fd:
303 | print(sub_data, file=fd)
304 |
305 |
306 | if __name__ == '__main__':
307 |
308 | args, _extra = arg_opts()
309 | filen = args.input_file
310 |
311 | if args.freq:
312 | rf_freq = int(args.freq)
313 |
314 | if args.default_freq:
315 | rf_freq_default = int(args.default_freq)
316 |
317 | if args.min_pulses:
318 | MIN_PULSES = int(args.min_pulses)
319 |
320 | if args.verb:
321 | verbose = args.verb
322 |
323 | main()
324 |
--------------------------------------------------------------------------------
/subghz_plot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 |
4 | ir_plot.py
5 |
6 | plot data from flipper subghz raw data save files
7 |
8 | Warning: this is 5 min hack code, use at own risk
9 |
10 | Written By: Peter Shipley github.com/evilpete
11 |
12 | From pkg https://github.com/evilpete/flipper_toolbox
13 |
14 | """
15 |
16 |
17 | import sys
18 | import os
19 | # from statistics import mean
20 | import argparse
21 | import statistics
22 | # from pprint import pprint
23 | import numpy as np
24 | # import pandas as pd
25 | import matplotlib.pyplot as plt
26 |
27 | verbose = 0
28 |
29 | PRINT_BITS = True # this is a hack
30 |
31 | LOW_PLOT_VAL = 1
32 | HIGH_PLOT_VAL = 5
33 |
34 | MIN_BIT_LEN = 1000
35 | DATA_SCALE = 10
36 |
37 |
38 | def arg_opts():
39 |
40 | parser = argparse.ArgumentParser(add_help=True, # noqa
41 | formatter_class=argparse.RawDescriptionHelpFormatter)
42 |
43 | parser.add_argument('-v', '--verbose', dest="verbose",
44 | default=0,
45 | help='Increase debug verbosity', action='count')
46 |
47 | parser.add_argument("-s", "--split", dest="split_sig",
48 | action='store_true',
49 | help="try to split and (sub)plot signals separately")
50 |
51 | parser.add_argument("-p", "--preamble", dest="preamble",
52 | type=int,
53 | default=0,
54 | help="split signal break length")
55 |
56 | parser.add_argument("-n", "--numplots", dest="numplots",
57 | type=int,
58 | default=0,
59 | help="maximum number of subplots")
60 |
61 | parser.add_argument("-l", "--length", dest="length",
62 | type=int,
63 | default=0,
64 | help="minimum signal bits")
65 |
66 | parser.add_argument("--seek", dest='seek',
67 | type=int,
68 | default=0,
69 | help="number of samples to skip")
70 |
71 | # parser.add_argument("-m", "--minpulse", dest="minbitlen",
72 | # type=int,
73 | # default=0,
74 | # help="minimum pause length")
75 |
76 | parser.add_argument("-f", "--file", dest="filename",
77 | default=None,
78 | help="Subghz Filename")
79 |
80 | parser.add_argument("-i", "--invert", dest="invert",
81 | default=False,
82 | action='store_true',
83 | help="Invert Wave plot")
84 |
85 | # parser.add_argument("-d", "--dir", dest="destdir",
86 | # default=None,
87 | # help="Destination")
88 |
89 | # parser.add_argument("-o", "--output", dest="out_format",
90 | # choices=['png', 'pdf', 'svg'],
91 | # default="None",
92 | # help="Output Format")
93 |
94 | # parser.add_argument("-s", "--screen", dest="screen",
95 | # default=False, action='store_true',
96 | # help="Display on Screen")
97 |
98 | # data_grp = parser.add_mutually_exclusive_group()
99 |
100 | return parser.parse_known_args()
101 |
102 |
103 | def split_data_str(dat, max_val=8000):
104 |
105 | ret = []
106 | cur_dat = []
107 |
108 | for x in dat:
109 | i = abs(x)
110 | if i > max_val:
111 | if cur_dat:
112 | ret.append(cur_dat)
113 | # print(f"cur_dat: {len(cur_dat)}")
114 | cur_dat = []
115 | else:
116 | cur_dat.append(x)
117 |
118 | ret.append(cur_dat)
119 |
120 | return ret
121 |
122 |
123 | def load_cmd_data(filename):
124 |
125 | ret = []
126 | with open(filename, 'r', encoding="utf-8") as fd:
127 |
128 | header = fd.readline().strip()
129 | if header != 'Filetype: Flipper SubGhz RAW File':
130 | print(f"Error: {filename} is not a Flipper SubGhz RAW file")
131 | sys.exit(1)
132 |
133 | for line in fd:
134 |
135 | line = line.strip()
136 |
137 | if not line or line[0] == '#': # skip blank lines
138 | continue
139 |
140 | if line.startswith("RAW_Data: "):
141 | a = line[10:].split()
142 | ret.extend(map(int, a))
143 |
144 | return ret
145 |
146 |
147 | def convert_dat(dat_list, invert=False, divider=0): # normalize=0,
148 |
149 | high_val = HIGH_PLOT_VAL
150 | low_val = LOW_PLOT_VAL
151 |
152 | if len(dat_list) % 2 != 0:
153 | dat_list.append(0)
154 |
155 | dat_len = len(dat_list)
156 |
157 | if verbose > 1:
158 | print(f"dat_len {dat_len}")
159 |
160 | if invert:
161 | high_val = LOW_PLOT_VAL
162 | low_val = HIGH_PLOT_VAL
163 |
164 | res = [low_val]
165 | for i in dat_list:
166 |
167 | if divider:
168 | i //= divider
169 |
170 | if i > 0:
171 | res += [high_val] * i
172 | else:
173 | res += [low_val] * abs(i)
174 |
175 | res.append(1)
176 |
177 | # print("\n")
178 | return res
179 |
180 |
181 | def main(arg, av):
182 |
183 | # disp = False
184 |
185 | # get input filename from argparse or fist arg
186 | if arg.filename:
187 | fname = arg.filename
188 | elif av:
189 | fname = av.pop(0)
190 |
191 | raw_dat = load_cmd_data(fname)
192 |
193 | if arg.seek:
194 | raw_dat = raw_dat[:arg.seek]
195 |
196 | # max_sig = max(raw_dat)
197 | # print(f"min {min_sig}")
198 | # print(f"max {max_sig}")
199 | # max_pause = int(statistics.mean(a_dat))
200 |
201 | a_dat = list(map(abs, raw_dat))
202 |
203 | # print(f"max_pause max//2 {max_pause}")
204 | # max_pause = int(statistics.mean(a_dat)) * 3
205 | max_pause = int(statistics.stdev(a_dat)) * 2
206 |
207 | max_pause = (arg.preamble or max_pause)
208 | # max(min_sig, max_sig) // 2)
209 |
210 | if verbose:
211 | print(f"max_pause {max_pause}")
212 |
213 | if arg.preamble or arg.split_sig:
214 | # print(f"using max_val {max_pause}")
215 | dat_list = split_data_str(raw_dat, max_val=max_pause)
216 | else:
217 | dat_list = [raw_dat]
218 |
219 | if verbose:
220 | print(f"dat_list {len(dat_list)}")
221 |
222 | min_length = (arg.length or MIN_BIT_LEN)
223 | plot_list = []
224 | for x in dat_list:
225 | y = convert_dat(x, divider=DATA_SCALE)
226 | if len(y) >= min_length:
227 | plot_list.append(convert_dat(x, divider=10))
228 |
229 | # print(f"plot_list {len(plot_list)}")
230 |
231 | # plot_list = plot_list[:8]
232 |
233 | if arg.numplots:
234 | plot_list = plot_list[:arg.numplots]
235 |
236 | list_lenghts = [len(x) for x in plot_list]
237 |
238 | max_len = max(list_lenghts)
239 |
240 | if verbose:
241 | print(f"max_len {max_len}")
242 |
243 | plot_x = np.arange(max_len*DATA_SCALE, step=DATA_SCALE)
244 |
245 | plt.style.use("dark_background")
246 | p = plt.figure() # facecolor='yellow')
247 | ax = p.gca()
248 | ax.get_yaxis().set_visible(False)
249 | plt.xlabel('μs')
250 |
251 | plt.title("SubGhz Raw Signal")
252 |
253 | height = 6
254 | pn = len(plot_list)
255 | if pn < 8:
256 | height = 2 + pn * .5
257 | plt.gcf().set_size_inches(6, height)
258 | # plt.figure(facecolor='yellow')
259 |
260 | y_off = 0
261 | for d in plot_list:
262 | d_len = len(d)
263 | # if d_len < max_len:
264 | # ln = max_len - d_len
265 | # d += [1] * ln
266 |
267 | plot_y = np.array(d) + (y_off * int(HIGH_PLOT_VAL * 1.3))
268 |
269 | plt.plot(plot_x[:d_len], plot_y)
270 |
271 | y_off += 1
272 |
273 | # if arg.out_format == 'png':
274 | # if arg.verbose:
275 | # print(f'{destdir}/{ii}_{cmd_name}.png y_off={y_off}')
276 | outfile = os.path.basename(fname)
277 | outfile = os.path.splitext(outfile)[0] + ".png"
278 | print(f"saving plot as {outfile}")
279 |
280 | plt.savefig(outfile, pad_inches=0.3)
281 |
282 | # if disp:
283 | plt.show()
284 |
285 |
286 | if __name__ == '__main__':
287 | ag, agv = arg_opts()
288 | # print("arg", arg, "av=", av)
289 |
290 | if ag.verbose:
291 | verbose = ag.verbose
292 |
293 | main(ag, agv)
294 |
--------------------------------------------------------------------------------
/subghz_preset_gen.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 |
4 | subghz_preset_gen.py
5 |
6 | Modify / Generates CC1101 "SubGhzPresetCustom" settings
7 |
8 | Written By: Peter Shipley github.com/evilpete
9 |
10 | From pkg https://github.com/evilpete/flipper_toolbox
11 |
12 | """
13 |
14 | # import sys
15 | # import os
16 | # import pprint
17 | import argparse
18 |
19 | from subghz_decode_presets import CC_Config # CC_REG
20 |
21 | # ppylint: disable=no-member
22 |
23 | _DEBUG = 0
24 |
25 |
26 | # See : https://github.com/flipperdevices/flipperzero-firmware/blob/dev/firmware/targets/f7/furi_hal/furi_hal_subghz_configs.h
27 |
28 |
29 | rf_presets = {
30 | # PresetOok270Async : OOK, bandwidth 270kHz, async
31 | "AM270": ("Custom_preset_data: 02 0D 03 47 08 32 0B 06 10 67 11 32 "
32 | "12 30 13 00 14 00 18 18 19 18 1B 03 1C 00 1D 40 20 FB "
33 | "21 B6 22 11 00 00 00 C0 00 00 00 00 00 00"),
34 |
35 | # PresetOok650Async : OOK, bandwidth 650kHz, async
36 | "AM650": ("Custom_preset_data: 02 0D 03 07 08 32 0B 06 10 17 11 32 "
37 | "12 30 13 00 14 00 18 18 19 18 1B 07 1C 00 1D 91 20 FB "
38 | "21 B6 22 11 00 00 00 C0 00 00 00 00 00 00"),
39 |
40 | # Preset2FSKDev238Async : FM, deviation 2.380371 kHz, async
41 | "FM238": ("Custom_preset_data: 02 0D 07 04 08 32 0B 06 10 67 11 83 "
42 | "12 04 13 02 14 00 15 04 18 18 19 16 1B 07 1C 00 1D 91 20 FB "
43 | "21 56 22 10 00 00 C0 00 00 00 00 00 00 00"),
44 |
45 | # Preset2FSKDev476Async : FM, deviation 47.60742 kHz, async
46 | "FM476": ("Custom_preset_data: 02 0D 07 04 08 32 0B 06 10 67 11 83 "
47 | "12 04 13 02 14 00 15 47 18 18 19 16 1B 07 1C 00 1D 91 20 FB "
48 | "21 56 22 10 00 00 C0 00 00 00 00 00 00 00"),
49 |
50 | # PresetMSK99_97KbAsync : MSK, deviation 47.60742 kHz, 99.97Kb/s, async
51 | "MSK999": ("Custom_preset_data: 02 06 03 07 04 46 05 4c 06 00 08 05 "
52 | "09 00 0a 00 0b 06 0c 23 10 5b 11 f8 12 72 13 22 14 f8 15 "
53 | "47 18 18 19 16 1a 1c 1b c7 1c 00 1d b2 21 56 22 10 29 59 "
54 | "00 00 c0 00 00 00 00 00 00 00"),
55 |
56 | # PresetGFSK9_99KbAsync : GFSK, deviation 19.042969 kHz, 9.996Kb/s, async
57 | "GFSK99": ("Custom_preset_data: 02 06 03 47 04 46 05 4c 06 00 08 05 "
58 | "09 00 0b 06 10 c8 11 93 12 12 15 34 18 18 19 16 1b 43 "
59 | "1c 40 1d 91 20 fb 00 00 c0 00 00 00 00 00 00 00"),
60 | }
61 |
62 |
63 | MOD_2FSK = 0x00
64 | MOD_GFSK = 0x10
65 | MOD_ASK_OOK = 0x30
66 | MOD_4FSK = 0x40
67 | MOD_MSK = 0x70
68 |
69 | PKT_FMT = {
70 | "Normal": 0x00,
71 | "Sync": 0x01,
72 | "Random": 0x02,
73 | "Async": 0x03,
74 | }
75 |
76 | mods = {
77 | "2FSK": 0x00, # MOD_2FSK,
78 | "GFSK": 0x10, # MOD_GFSK,
79 | "OOK": 0x30, # MOD_ASK_OOK
80 | "4FSK": 0x40, # MOD_4FSK
81 | "MSK": 0x70, # MOD_MSK
82 | }
83 |
84 | sync_modes = ['SYNCM_NONE', 'SYNCM_15_of_16', 'SYNCM_16_of_16',
85 | 'SYNCM_30_of_32', 'SYNCM_CARRIER', 'SYNCM_CARRIER_15_of_16',
86 | 'SYNCM_CARRIER_16_of_16', 'SYNCM_CARRIER_30_of_32']
87 |
88 | sync_help = """
89 | SYNCM_NONE = 0
90 | SYNCM_15_of_16 = 1
91 | SYNCM_16_of_16 = 2
92 | SYNCM_30_of_32 = 3
93 | SYNCM_CARRIER = 4
94 | SYNCM_CARRIER_15_of_16 = 5
95 | SYNCM_CARRIER_16_of_16 = 6
96 | SYNCM_CARRIER_30_of_32 = 7
97 | """
98 |
99 |
100 | def _interpret_val(opt):
101 | opt = opt.upper()
102 |
103 | if opt in ["ON", "TRUE", "T", "YES", "Y", "1"]:
104 | return 1
105 |
106 | if opt in ["OFF", "FALSE", "F", "NO", "N", "0"]:
107 | return 0
108 |
109 | if opt.isdigit():
110 | return int(opt)
111 |
112 | return None
113 |
114 |
115 | def arg_opts():
116 | """argument parse"""
117 |
118 | preset_namelist = sorted(rf_presets.keys())
119 | modulation_namelist = sorted(CC_Config.mod_num.values())
120 | length_namelist = sorted(CC_Config.PKT_LENGTH_CONF.keys())
121 | pkt_fmt_namelist = sorted(PKT_FMT.keys())
122 | # modulation_namelist = sorted(mods.keys())
123 | # length_namelist = sorted(length_conf.keys())
124 |
125 | parser = argparse.ArgumentParser(add_help=True, allow_abbrev=True,
126 | formatter_class=argparse.RawDescriptionHelpFormatter)
127 | # argument_default=argparse.SUPPRESS,
128 |
129 | parser.add_argument("-p", "--preset", dest="preset_profile",
130 | choices=preset_namelist,
131 | default=None,
132 | help="preset profile")
133 |
134 | parser.add_argument("-pr", "--print", dest="print_profile",
135 | action='store_true',
136 | default=None,
137 | help="Print Profile Description")
138 |
139 | parser.add_argument("-sw", "--syncword", dest="sync_word",
140 | type=int,
141 | # choices=sync_modes,
142 | default=None,
143 | help="Sync Word")
144 |
145 | parser.add_argument("-sm", "--syncmode", dest="sync_mode",
146 | type=int,
147 | # choices=sync_modes,
148 | default=None,
149 | help=sync_help)
150 |
151 | parser.add_argument("-mod", "--modulation", dest="modulation",
152 | choices=modulation_namelist,
153 | default=None,
154 | help="Modulation")
155 |
156 | parser.add_argument("-lc", "--length_conf", dest="length_conf",
157 | choices=length_namelist,
158 | default=None,
159 | help="Length Config")
160 |
161 | parser.add_argument("-pf", "--pktfmt", dest="pkt_fmt",
162 | choices=pkt_fmt_namelist,
163 | default="Async",
164 | help="Packet Format")
165 |
166 | parser.add_argument("-pl", "--pkt_len", dest="pkt_len",
167 | type=int,
168 | default=None,
169 | help="Packet Length")
170 |
171 | parser.add_argument('-v', '--verbose', dest="verbose",
172 | default=0,
173 | help='Increase debug verbosity', action='count')
174 |
175 | parser.add_argument("-n", "--name", dest="conf_name",
176 | default="NewPreset",
177 | help="Name For Preset")
178 |
179 | parser.add_argument("-if", "--IntermediateFreq", dest="intermediate_freq",
180 | type=int,
181 | default=None,
182 | help="Intermediate frequency")
183 |
184 | parser.add_argument("-dr", "--datarate", dest="data_rate",
185 | type=int,
186 | default=None,
187 | help="Date Rate")
188 |
189 | parser.add_argument("-fr", "--frequency", dest="frequency",
190 | type=int,
191 | default=None,
192 | help="frequency")
193 |
194 | parser.add_argument("-bw", "--bandwidth", dest="band_width",
195 | type=int,
196 | default=None,
197 | help="Band Width")
198 |
199 | parser.add_argument("-np", "--numpreamble", dest="num_preamble",
200 | type=int,
201 | default=None,
202 | help="Minimum number of preamble bytes to be transmitted\n"
203 | "0=2bytes 1=3b 2=4b 3=6b 4=8b 5=12b 6=15b 7=24b"
204 | )
205 |
206 | parser.add_argument("-dev", "--deviation", dest="deviation",
207 | type=int,
208 | default=None,
209 | help="FM Deviation")
210 |
211 | parser.add_argument("-cs", "--channelspacing", "--spacing", dest="channel_spacing",
212 | type=int,
213 | default=None,
214 | help="Channel Spacing")
215 |
216 | parser.add_argument("-man", "--manchester", dest="manchester",
217 | default=False, action='store_true',
218 | help="Manchester Encoding")
219 |
220 | # crc_grp = parser.add_mutually_exclusive_group()
221 |
222 | parser.add_argument("-crc", "--enable_crc", dest="enable_crc",
223 | choices=['on', 'off'],
224 | default=None,
225 | help="Enable/Disable CRC")
226 |
227 | parser.add_argument("-dw", "--datawhitening", "--datawhite", dest="data_whiten",
228 | choices=['on', 'off'],
229 | default=None,
230 | help="Enable/DisableData Whitening")
231 |
232 |
233 | # data_grp.add_argument("-c", "--cmd-file", dest="cmd_file",
234 | # type=argparse.FileType('r', encoding='UTF-8'),
235 | # default=None,
236 | # help="Command File")
237 |
238 | return parser.parse_known_args()
239 |
240 |
241 | def main():
242 |
243 | # print(rf_presets)
244 |
245 | reg_conf = CC_Config()
246 | reg_conf.reg_list[2] = 13 # Output Pin Configuration
247 | reg_conf.reg_list[3] = 7 # RX FIFO and TX FIFO Thresholds
248 |
249 |
250 | args, u = arg_opts()
251 |
252 | # print(f"args: {args}\n")
253 | # print(f"u: {u}\n")
254 |
255 | if args.preset_profile:
256 | reg_conf.load_str(rf_presets[args.preset_profile])
257 |
258 | if args.deviation is not None:
259 | reg_conf.set_Deviatn(args.deviation)
260 |
261 | if args.modulation is not None:
262 | reg_conf.set_Modulation(args.modulation)
263 |
264 | if args.manchester is not None:
265 | reg_conf.set_Manchester(args.manchester)
266 |
267 | if args.length_conf is not None:
268 | reg_conf.set_Pktlen_conf(args.length_conf)
269 |
270 | if args.pkt_len is not None:
271 | if args.pkt_len > 255:
272 | raise ValueError("Max Packet Length 255")
273 | reg_conf.set_pktlen(args.pkt_len)
274 |
275 | if args.intermediate_freq is not None:
276 | reg_conf.set_FsIF(args.intermediate_freq)
277 |
278 | if args.data_rate is not None:
279 | reg_conf.set_DRate(args.data_rate)
280 |
281 | if args.channel_spacing is not None:
282 | reg_conf.set_ChanSpc(args.channel_spacing)
283 |
284 | if args.enable_crc is not None:
285 | if args.enable_crc == 'on':
286 | reg_conf.set_Enable_CRC(enable=True)
287 | else:
288 | reg_conf.set_Enable_CRC(enable=False)
289 |
290 | if args.data_whiten is not None:
291 | if args.data_whiten == 'yes':
292 | reg_conf.set_PktDataWhitening(1)
293 | else:
294 | reg_conf.set_PktDataWhitening(0)
295 |
296 | if args.num_preamble is not None:
297 | reg_conf.set_NumPreamble(args.num_preamble)
298 |
299 | if args.band_width is not None:
300 | if args.band_width < 54170:
301 | raise ValueError("Bandwith must me over 54kHz")
302 | reg_conf.set_ChanBW(args.band_width)
303 |
304 | if args.frequency is not None:
305 | reg_conf.set_Freq(args.frequency)
306 | print("Warning: frequency is set in subghz flipper file")
307 |
308 | if args.pkt_fmt is not None:
309 | if args.pkt_fmt in PKT_FMT:
310 | reg_conf.set_pktfmt(args.pkt_fmt)
311 |
312 | mod = reg_conf.get_Modulation()
313 | manch = reg_conf.get_Manchester()
314 |
315 | if mod == 0x30 and args.deviation:
316 | print("Warning: Deviation value is ignored when modulation is 'OOK'")
317 |
318 | if mod is not None and manch is not None:
319 | if args.modulation == 0x40 and manch:
320 | print("Warning: radio doesn't support Manchester encoding in 4FSK")
321 |
322 | # print("as_preset_tuples:\n", pprint.pformat(reg_conf.as_preset_data_tuples(), compact=True))
323 |
324 | print("\n")
325 | print(f"Custom_preset_name: {args.conf_name}\n"
326 | "Custom_preset_module: CC1101\n"
327 | "Custom_preset_data:", reg_conf.as_preset_data())
328 | print("\n")
329 |
330 | if args.print_profile:
331 | for a, b in reg_conf.rf_conf():
332 | print(f" {a:<28s} {b:<10s}")
333 |
334 | # print(reg_conf.as_tuples())
335 |
336 |
337 | if __name__ == '__main__':
338 | main()
339 |
--------------------------------------------------------------------------------
/subghz_secplusv1.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | Display and/or edit Flipper SubGhz Security+ 1.0 Key Files
4 |
5 | Peter Shipley github.com/evilpete
6 |
7 | From pkg https://github.com/evilpete/flipper_toolbox
8 | """
9 |
10 | # **WORK IN PROGRESS**
11 |
12 | import sys
13 | import time
14 | # import os
15 | # from typing import Iterable, Union, Any
16 | import random
17 | import argparse
18 |
19 | _debug = 0
20 |
21 | MAX_FIXED = 3**20 - 1
22 | MAX_ID = 3**17 - 1
23 | TX_FREQ = 315000000
24 |
25 | BUTTON_NAMES = ["Middle", "Left", "Right"]
26 |
27 |
28 | # https://stackoverflow.com/questions/2267362/how-to-convert-an-integer-to-a-string-in-any-base
29 | def numToBase(n, b):
30 | if n == 0:
31 | return [0]
32 | digits = []
33 | while n:
34 | digits.append(int(n % b))
35 | n //= b
36 | return digits[::-1]
37 |
38 |
39 | def numToBase_str(n, b):
40 | a = numToBase(n, b)
41 | rstr = map(str, a)
42 | return "".join(rstr)
43 |
44 |
45 | def arg_opts():
46 |
47 | parser = argparse.ArgumentParser(add_help=True, allow_abbrev=True, # noqa
48 | description="display and/or edit Flipper SubGhz Security+ 1.0 Key Files",
49 | formatter_class=argparse.RawDescriptionHelpFormatter
50 | )
51 | # argument_default=argparse.SUPPRESS,
52 |
53 | parser.add_argument("-r", "--rolling", metavar='rolling_code', dest="rolling",
54 | default=None,
55 | help="Rolling Count")
56 |
57 | parser.add_argument("-b", "--button", metavar='button_id', dest="button",
58 | # type=int,
59 | default=None,
60 | help="Button: 0=Middle 1=Left 2=Right")
61 |
62 | fixed_grp = parser.add_mutually_exclusive_group()
63 |
64 | fixed_grp.add_argument("-f", "--fixed", metavar='fixed_code', dest="fixed",
65 | default=0,
66 | help="fixed code value")
67 |
68 | fixed_grp.add_argument("-i", "--id", metavar='remote_id', dest="id",
69 | default=None,
70 | help="Remote-ID")
71 |
72 | parser.add_argument("-q", "--quiet", dest="quiet",
73 | default=None,
74 | action='store_true',
75 | help="run quietly")
76 |
77 | parser.add_argument("-o", "--out", metavar='output_filename', dest="outfname",
78 | default=None,
79 | help="output filename, use '-' for stdout")
80 |
81 | parser.add_argument("input_file", metavar='input-file', nargs='?',
82 | # "-F", "--File", dest="input_file",
83 | # type=argparse.FileType('r', encoding='UTF-8'),
84 | default=None,
85 | help="Flipper Subghz File")
86 |
87 | # parser.add_argument("-h", "--freq", "--hz", dest="send_freq",
88 | # type=int,
89 | # default=315000000,
90 | # help="Transmit frequency")
91 |
92 | ar, gs = parser.parse_known_args()
93 |
94 | ar.rolling = conv_int(ar.rolling)
95 | ar.fixed = conv_int(ar.fixed)
96 | ar.id = conv_int(ar.id)
97 |
98 | if ar.rolling and int(ar.rolling) >= 2**32:
99 | raise ValueError("Rolling code must be less than 2^32")
100 |
101 | if ar.fixed and int(ar.fixed) >= MAX_FIXED:
102 | raise ValueError(f"Fixed code must be less than 3^20 ({MAX_FIXED})")
103 |
104 | if ar.id and int(ar.id) > MAX_ID:
105 | raise ValueError(f"Remote ID must be less than 3^17 ({MAX_ID})")
106 |
107 | # ar.button.isdigit() and int(ar.button) <= 2:
108 | if ar.button and ar.button not in ['0', '1', '2']:
109 | raise ValueError(f"Button value must be between 0 -> 2 ({ar.button})")
110 |
111 | return ar, gs
112 |
113 |
114 | SUBGHZ_KEY_FILE_TYPE = "Flipper SubGhz Key File"
115 |
116 |
117 | def read_file(fd):
118 |
119 | key_dat = None
120 | header = fd.readline().strip()
121 |
122 | a = header.split(':', 1)
123 | if not (a[0].startswith("Filetype")
124 | and a[1].strip() == SUBGHZ_KEY_FILE_TYPE):
125 | print("invalid filetype")
126 | sys.exit(0)
127 |
128 | for line in fd:
129 | a = line.split(':', 1)
130 |
131 | if a[0].startswith("Protocol"):
132 | if a[1].strip() != "Security+ 1.0":
133 | sys.exit(0)
134 |
135 | if a[0].startswith("Key"):
136 | key_dat = a[1].strip().split()
137 |
138 | if _debug:
139 | print("read_file", key_dat)
140 |
141 | if key_dat:
142 | # return "".join(key_dat), "".join(pkt_dat)
143 | return key_dat
144 |
145 | return None
146 |
147 |
148 | def write_file(rol, fix, fname=None, quiet=False):
149 |
150 | hf = f"{fix:08X}"
151 | hr = f"{rol:08X}"
152 | # print(f"1: {ha}")
153 | # print(f"2: {hb}")
154 | hval = hf + hr
155 |
156 | key_str = " ".join([hval[i:i + 2] for i in range(0, 16, 2)])
157 |
158 | comment_str = pretty_print(rol, fix)
159 |
160 | # Id:{fix // 27:08X} ({fix // 27}) Rolling:{rol:02X} ({rol})
161 | ret = f"""Filetype: Flipper SubGhz Key File
162 | Version: 1
163 | # Generated with https://github.com/evilpete/flipper_toolbox
164 | # {time.ctime()}
165 | # {comment_str}
166 | Frequency: {TX_FREQ}
167 | Preset: FuriHalSubGhzPresetOok650Async
168 | Protocol: Security+ 1.0
169 | Bit: 42
170 | Key: {key_str}
171 | """ # noqa
172 |
173 | if _debug:
174 | print(ret)
175 | print(ret)
176 |
177 | if fname is None:
178 | fname = f"secv1-{fix:010X}.sub"
179 |
180 | if fname == '-':
181 | sys.stdout.write(ret)
182 | else:
183 | if not fname.endswith('.sub'):
184 | fname += '.sub'
185 |
186 | if not quiet:
187 | print(f"writting: {fname}")
188 |
189 | with open(fname, "w", encoding="utf-8") as fd:
190 | fd.write(ret)
191 |
192 |
193 | # SUBGHZ_KEY_FILE_TYPE "Flipper SubGhz Key File"
194 |
195 | hex_set = set('abcdefABCDEF0123456789')
196 |
197 |
198 | def is_hex_str(s):
199 | return set(s).issubset(hex_set)
200 |
201 |
202 | def conv_int(arg):
203 |
204 | if arg == 0:
205 | return 0
206 |
207 | if not arg:
208 | return None
209 |
210 | if arg[:2].lower() in ['0b', '0x']:
211 | return int(arg, 0)
212 |
213 | if arg.isdigit():
214 | return int(arg)
215 |
216 | if is_hex_str(arg):
217 | return int(arg, 16)
218 |
219 | return None
220 |
221 |
222 | def pretty_print(rolling, fixed):
223 |
224 | ret_str = f"Rolling={rolling},"
225 | ret_str += f" Fixed={fixed},"
226 |
227 | fixed_b3 = numToBase_str(fixed, 3)
228 |
229 | b_id = fixed_b3[-1] # a_base3.pop(0)
230 | id0 = fixed_b3[-2]
231 | id1 = fixed_b3[-3]
232 |
233 | if id1 == "1":
234 | remote_id3 = fixed_b3[:-3]
235 | remote_id = int(remote_id3, 3)
236 |
237 | button_id = BUTTON_NAMES[int(b_id)]
238 |
239 | ret_str += f" id0={id0}, id1={id1},"
240 | ret_str += f" Remote_id={remote_id} ({remote_id:08X}),"
241 | ret_str += f" Button_id={button_id} ({b_id})"
242 |
243 | elif id1 == "0":
244 | pad_id3 = fixed_b3[-10:-3]
245 | pad_id = int(pad_id3, 3)
246 | pin3 = fixed_b3[-19:-10]
247 | pin = int(pin3, 3)
248 |
249 | ret_str += f" pad_id={pad_id}"
250 | if pin <= 9999:
251 | ret_str += f" pin={0:04}"
252 | elif pin <= 11029:
253 | ret_str += f" pin=Enter ({pin})"
254 |
255 | pin_suffix = fixed_b3[0]
256 | if pin_suffix == "1":
257 | ret_str += " #"
258 | elif pin_suffix == "2":
259 | ret_str += " *"
260 |
261 | return ret_str
262 |
263 |
264 | def main():
265 |
266 | rolling_dat = fixed_dat = 0
267 |
268 | args, _extra = arg_opts()
269 |
270 | if _debug:
271 | print("args", args)
272 | print("_extra", _extra)
273 |
274 | if args.input_file:
275 | with open(args.input_file, 'r', encoding='UTF-8') as fd:
276 | xx = read_file(fd)
277 |
278 | if xx:
279 | s_key = "".join(xx)
280 | i_key = int(s_key, 16)
281 | b_key = f"{i_key:08b}"
282 |
283 | if _debug:
284 | print(s_key)
285 | print(i_key)
286 | print(b_key[6:])
287 |
288 | fixed_dat = (i_key >> 32) & 0xFFFFFFFF
289 |
290 | rolling_dat = i_key & 0xFFFFFFFF
291 |
292 | if _debug: # and (fixed_out or rolling_out):
293 | print(f">> fixed_dat {fixed_dat:12d} "
294 | f"{fixed_dat:010X} {fixed_dat:016b} "
295 | + numToBase_str(fixed_dat, 3))
296 | print(f">> rolling_dat {rolling_dat:12d} "
297 | f"{rolling_dat:010X} {rolling_dat:040b} "
298 | + numToBase_str(rolling_dat, 3))
299 |
300 | a_fixed = args.fixed or fixed_dat
301 |
302 | a_id0 = a_id1 = a_remote_id = a_but = None
303 |
304 | if a_fixed:
305 | a_base3 = numToBase_str(a_fixed, 3)
306 | a_but = a_base3[-1] # a_base3.pop(0)
307 | a_id0 = a_base3[-2]
308 | a_id1 = a_base3[-3]
309 | a_remote_id3 = a_base3[:-3]
310 | a_remote_id = int(a_remote_id3, 3)
311 |
312 | r_but = args.button or a_but or 1
313 |
314 | # 129140162
315 | r_id = args.id or a_remote_id or random.randint(2**22, MAX_ID - 1)
316 |
317 | r_rolling = (args.rolling or rolling_dat or 1) & 0xFFFFFFFF # 32 bits max
318 |
319 | # fixed_code = (r_id & 0xffffffff) | (r_button << 32)
320 |
321 | # button_code = random.randint(3, 172) | 0x01
322 |
323 | if _debug:
324 | print(f"r_button {r_but}")
325 | print(f"r_id {r_id:12d} {r_id:010X} {r_id:016b}", numToBase_str(r_id, 3))
326 | print(f"r_rolling {r_rolling:12d} {r_rolling:010X} {r_rolling:016b}", numToBase_str(r_rolling, 3))
327 | # print(f"fixed_code {fixed_code:12d} {fixed_code:010X} {fixed_code:040b}") # noqa
328 |
329 | r_id3 = numToBase_str(r_id, 3)
330 | r_id0 = a_id0 or "0"
331 | r_id1 = a_id1 or "1"
332 |
333 | r_fixed3 = r_id3 + r_id1 + r_id0 + str(r_but)
334 |
335 | r_fixed = int(r_fixed3, 3)
336 | # print(f"r_fixed {r_fixed:12d} {r_rolling:010X} {r_fixed:016b} {r_fixed3}")
337 |
338 | if not args.quiet:
339 | pretty_out = pretty_print(r_rolling, r_fixed)
340 | print(f"\nSecurity+ V1: {pretty_out}\n")
341 |
342 | # only save to file if new of changed
343 | if (args.fixed or args.button or args.id or args.rolling) or not fixed_dat:
344 | write_file(r_rolling, r_fixed, args.outfname, args.quiet)
345 |
346 |
347 | if __name__ == '__main__':
348 | main()
349 |
--------------------------------------------------------------------------------
/subghz_secplusv2.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | """
4 | Display and/or edit Flipper SubGhz Security+ 2.0 Key Files
5 |
6 | Peter Shipley github.com/evilpete
7 |
8 | From pkg https://github.com/evilpete/flipper_toolbox
9 | """
10 |
11 | # **WORK IN PROGRESS**
12 |
13 | import sys
14 | import os
15 | import time
16 |
17 | # from typing import Iterable, Union, Any
18 | import random
19 | import json
20 | import argparse
21 | import pprint
22 |
23 | try:
24 | import secplus.secplus as Secplus
25 | except ImportError as e:
26 | print("Failed to import secplus")
27 | print("https://github.com/argilo/secplus/blob/master/secplus.py")
28 | sys.exit(0)
29 |
30 | _debug = 0
31 |
32 | TX_FREQ = 315000000
33 |
34 |
35 | def arg_opts():
36 | parser = argparse.ArgumentParser(
37 | add_help=True,
38 | allow_abbrev=True, # noqa
39 | description="display and/or edit Flipper SubGhz Security+ 2.0 Key Files", # noqa
40 | formatter_class=argparse.RawDescriptionHelpFormatter,
41 | )
42 | # argument_default=argparse.SUPPRESS,
43 |
44 | parser.add_argument(
45 | "-r",
46 | "-rolling",
47 | metavar="rolling_code",
48 | dest="rolling",
49 | default=None,
50 | help="Rolling Count",
51 | )
52 |
53 | parser.add_argument(
54 | "-b", "--button", metavar="button_id", dest="button", default=0, help="Button"
55 | )
56 |
57 | fixed_grp = parser.add_mutually_exclusive_group()
58 |
59 | fixed_grp.add_argument(
60 | "-f",
61 | "--fixed",
62 | metavar="fixed_code",
63 | dest="fixed",
64 | default=0,
65 | help="fixed code value",
66 | )
67 |
68 | fixed_grp.add_argument(
69 | "-i", "--id", metavar="remote_id", dest="id", default=None, help="Remote-ID"
70 | )
71 |
72 | parser.add_argument(
73 | "-q",
74 | "--quiet",
75 | dest="quiet",
76 | default=None,
77 | action="store_true",
78 | help="run quietly",
79 | )
80 |
81 | parser.add_argument(
82 | "-J",
83 | "--Json",
84 | metavar="rtl_log.json",
85 | dest="json_log",
86 | default=None,
87 | help="Read rtl_433 json log",
88 | )
89 |
90 | parser.add_argument(
91 | "-o",
92 | "--out",
93 | metavar="output_filename",
94 | dest="outfname",
95 | default=None,
96 | help="output filename, use '-' for stdout",
97 | )
98 |
99 | parser.add_argument(
100 | "input_file",
101 | metavar="input-file",
102 | nargs="?",
103 | default=None,
104 | help="Flipper Subghz File",
105 | )
106 |
107 | # parser.add_argument("-h", "--freq", "--hz", dest="send_freq",
108 | # type=int,
109 | # default=315000000,
110 | # help="Transmit frequency")
111 |
112 | ar, gs = parser.parse_known_args()
113 |
114 | ar.rolling = conv_int(ar.rolling)
115 | ar.id = conv_int(ar.id)
116 | ar.fixed = conv_int(ar.fixed)
117 | ar.button = conv_int(ar.button)
118 |
119 | return ar, gs
120 |
121 |
122 | # Filetype: Flipper SubGhz Key File
123 | # Version: 1
124 | # Frequency: 315000000
125 | # Preset: FuriHalSubGhzPresetOok650Async
126 | # Protocol: Security+ 2.0
127 | # Bit: 62
128 | # Key: 00 00 3D 10 02 09 FA F6
129 | # Secplus_packet_1: 00 00 3C 29 37 7F 38 F3
130 |
131 | SUBGHZ_KEY_FILE_TYPE = "Flipper SubGhz Key File"
132 |
133 |
134 | def read_file(fd):
135 | key_dat = pkt_dat = None
136 | header = fd.readline().strip()
137 |
138 | a = header.split(":", 1)
139 | if not (a[0].startswith("Filetype") and a[1].strip() == SUBGHZ_KEY_FILE_TYPE):
140 | print("invalid filetype")
141 | sys.exit(0)
142 |
143 | for line in fd:
144 | a = line.split(":", 1)
145 |
146 | if a[0].startswith("Protocol"):
147 | if a[1].strip() != "Security+ 2.0":
148 | print("invalid Protocol")
149 | sys.exit(0)
150 |
151 | if a[0].startswith("Key"):
152 | key_dat = a[1].strip().split()
153 |
154 | if a[0].startswith("Secplus_packet_1"):
155 | pkt_dat = a[1].strip().split()
156 | # replace(" ", "")
157 |
158 | if _debug:
159 | print("read_file", key_dat, pkt_dat)
160 |
161 | if key_dat and pkt_dat:
162 | return "".join(key_dat), "".join(pkt_dat)
163 | # return key_dat, pkt_dat
164 |
165 | return None, None
166 |
167 |
168 | def print_file(rol, fix, fname=None, quiet=False, rf_freq=None):
169 | seq_v2 = Secplus.encode_v2(rol, fix)
170 | seq_v2_str = "".join(map(str, seq_v2))
171 | if _debug:
172 | print(seq_v2_str[:40], "---", seq_v2_str[40:])
173 |
174 | ia = int("00000000001111" + "00" + seq_v2_str[:40], 2)
175 | ib = int("00000000001111" + "01" + seq_v2_str[40:], 2)
176 |
177 | ha = f"{ia:016X}"
178 | hb = f"{ib:016X}"
179 | # print(f"1: {ha}")
180 | # print(f"2: {hb}")
181 |
182 | p1_str = " ".join([ha[i: i + 2] for i in range(0, 16, 2)])
183 | p2_str = " ".join([hb[i: i + 2] for i in range(0, 16, 2)])
184 |
185 | tx_freq = rf_freq or TX_FREQ
186 |
187 | ret = f"""Filetype: Flipper SubGhz Key File
188 | Version: 1
189 | # Button:{fix>>32:02X} ({fix>>32}) Id:{fix&0xffffffff:08X} ({fix&0xffffffff}) Rolling:{rol:02X} ({rol})
190 | # Generated with https://github.com/evilpete/flipper_toolbox
191 | # {time.ctime()}
192 | Frequency: {tx_freq}
193 | Preset: FuriHalSubGhzPresetOok650Async
194 | Protocol: Security+ 2.0
195 | Bit: 62
196 | Key: {p2_str}
197 | Secplus_packet_1: {p1_str}
198 | """ # noqa
199 |
200 | if _debug:
201 | print(ret)
202 |
203 | if fname is None:
204 | fname = f"secv2-{fix:010X}.sub"
205 | elif os.path.isdir(fname):
206 | fname = f"{fname}/secv2-{fix:010X}.sub"
207 |
208 | if fname == "-":
209 | sys.stdout.write(ret)
210 | else:
211 | if not fname.endswith(".sub"):
212 | fname += ".sub"
213 |
214 | if not quiet:
215 | print(f"writting: {fname}")
216 |
217 | with open(fname, "w", encoding="utf-8") as fd:
218 | fd.write(ret)
219 |
220 |
221 | # SUBGHZ_KEY_FILE_TYPE "Flipper SubGhz Key File"
222 |
223 | hex_set = set("abcdefABCDEF0123456789")
224 |
225 |
226 | def is_hex_str(s):
227 | return set(s).issubset(hex_set)
228 |
229 |
230 | def conv_int(arg):
231 | if arg == 0:
232 | return 0
233 |
234 | if not arg:
235 | return None
236 |
237 | if arg[:2].lower() in ["0b", "0x"]:
238 | return int(arg, 0)
239 |
240 | if arg.isdigit():
241 | return int(arg)
242 |
243 | if is_hex_str(arg):
244 | return int(arg, 16)
245 |
246 | return None
247 |
248 |
249 | # {"time" : "@1.548164s", "model" : "Secplus-v2", "id" : 1959100928,
250 | # "button_id" : 16, "remote_id" : 1959100928, "fixed" : "70678577664",
251 | # "rolling" : "240124739"}
252 | #
253 | # { "time": "@1.198481s", "model": "Secplus-v2", "id": 1082192868,
254 | # "button_id": 161, "remote_id": 1082192868, "fixed": "692571927524",
255 | # "rolling": "24", "packet_1": "018c3492a980", "packet_2": "4804027ebd80",
256 | # "mod": "ASK", "freq": 310.032,
257 | # "rssi": -0.113, "snr": 25.31, "noise": -25.423 }
258 |
259 |
260 | def grok_json(args):
261 | id_list = {}
262 | with open(args.json_log, "r", encoding="UTF-8") as fd:
263 | js = {}
264 | for line in fd:
265 | try:
266 | js = json.loads(line)
267 | except json.JSONDecodeError as _e:
268 | if _debug:
269 | print(_e.msg)
270 | print(_e.doc)
271 | continue
272 |
273 | fid = js.get("fixed", None)
274 | rol = js.get("rolling", None)
275 |
276 | if fid is None or rol is None:
277 | continue
278 |
279 | id_list[fid] = js
280 |
281 | if _debug:
282 | pprint.pprint(id_list)
283 |
284 | for p in id_list.values():
285 | fr = p.get("freq", None)
286 | if fr:
287 | fr = int((fr // 1) * 1000000)
288 |
289 | p_rolling = int(p["rolling"])
290 | p_fixed = int(p["fixed"])
291 | print_file(
292 | p_rolling, p_fixed, fname=args.outfname, quiet=args.quiet, rf_freq=fr
293 | )
294 |
295 |
296 | def main():
297 | rolling_out = fixed_out = 0
298 |
299 | args, _extra = arg_opts()
300 |
301 | if args.json_log:
302 | grok_json(args)
303 | return
304 |
305 | if _debug:
306 | print("args", args)
307 | print("_extra", _extra)
308 |
309 | if args.input_file:
310 | b_pkt1 = b_key = None
311 | with open(args.input_file, "r", encoding="UTF-8") as fd:
312 | xx, yy = read_file(fd)
313 |
314 | if xx:
315 | f_key = "".join(xx)
316 | b_key = f"{int(f_key, 16):08b}"
317 |
318 | if yy:
319 | f_pkt1 = "".join(yy)
320 | b_pkt1 = f"{int(f_pkt1, 16):08b}"
321 |
322 | if _debug:
323 | print(f_pkt1, " : ", f_key)
324 | print(b_pkt1[6:], " : ", b_key[6:])
325 | print(len(b_pkt1[6:]), len(b_key[6:]))
326 |
327 | full_pkt = b_pkt1[6:] + b_key[6:]
328 |
329 | if _debug:
330 | print("full =", full_pkt)
331 |
332 | full_pkt_list = list(map(int, list(full_pkt)))
333 | rolling_out, fixed_out, _data = Secplus.decode_v2(full_pkt_list)
334 |
335 | if _debug: # and (fixed_out or rolling_out):
336 | print(
337 | f">> rolling_out {rolling_out:12d} "
338 | f"{rolling_out:010X} {rolling_out:016b}"
339 | )
340 | print(f">> fixed_out {fixed_out:12d} " f"{fixed_out:010X} {fixed_out:040b}")
341 | pretty_out = Secplus.pretty_v2(rolling_out, fixed_out)
342 | print(">>", pretty_out)
343 |
344 | a_fixed = args.fixed or fixed_out
345 | # a_rolling = args.rolling or rolling_out
346 |
347 | r_button = args.button or (a_fixed >> 32) or 91 # 8 bits
348 | r_button &= 0xFF
349 |
350 | r_id = args.id or a_fixed or random.randint(2**23, 2**31) # 32 bits id
351 | r_id &= 0xFFFFFFFF
352 |
353 | r_rolling = (args.rolling or rolling_out or 1) & 0x0FFFFFFF # 28 bits max
354 |
355 | fixed_code = (r_id & 0xFFFFFFFF) | (r_button << 32)
356 |
357 | # button_code = random.randint(3, 172) | 0x01
358 |
359 | if _debug:
360 | print(f"r_button {r_button:12d} {r_button:10X} {r_button:>08b}")
361 | print(f"r_id {r_id:12d} {r_id:010X} {r_id:016b}")
362 | print(f"r_rolling {r_rolling:12d} {r_rolling:010X} {r_rolling:016b}")
363 | print(
364 | f"fixed_code {fixed_code:12d} {fixed_code:010X} {fixed_code:040b}"
365 | ) # noqa
366 |
367 | if not args.quiet:
368 | pretty_out = Secplus.pretty_v2(r_rolling, fixed_code)
369 | print(f"\n{pretty_out}\n")
370 |
371 | # only save to file if new of changed
372 | if (args.fixed or args.button or args.id or args.rolling) or not fixed_out:
373 | print_file(r_rolling, fixed_code, args.outfname, args.quiet)
374 |
375 |
376 | if __name__ == "__main__":
377 | main()
378 |
--------------------------------------------------------------------------------
/subghz_x10.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | Generate X10 RF command in Flipper .sub format
4 |
5 | Peter Shipley github.com/evilpete
6 |
7 | From pkg https://github.com/evilpete/flipper_toolbox
8 | """
9 |
10 | import sys
11 | import time
12 |
13 |
14 | # Usage;
15 | # ./subghz_x10.py [On|Off]
16 | # Example:
17 | # ./subghz_x10.py B10 on
18 | #
19 | # ./subghz_x10.py B10 Dim Dim Dim
20 | #
21 | # or
22 | #
23 | # Generate a ALL-OFF / ALL-ON for all housecodes
24 | # ./subghz_x10.py -b
25 | #
26 |
27 | # https://www.laser.com/dhouston/rf.html
28 |
29 |
30 | _debug = 0
31 |
32 | # Freq is 310MHz in North America
33 | # 433.92MHz in Europe
34 |
35 | rf_freq = 310000000
36 |
37 | houseCodes = {
38 | "A": 0x60, # 01100000
39 | "B": 0x70, # 01110000
40 | "C": 0x40, # 01000000
41 | "D": 0x50, # 01010000
42 | "E": 0x80, # 10000000
43 | "F": 0x90, # 10010000
44 | "G": 0xA0, # 10100000
45 | "H": 0xB0, # 10110000
46 | "I": 0xE0, # 11100000
47 | "J": 0xF0, # 11110000
48 | "K": 0xC0, # 11000000
49 | "L": 0xD0, # 11010000
50 | "M": 0x00, # 00000000
51 | "N": 0x10, # 00010000
52 | "O": 0x20, # 00100000
53 | "P": 0x30, # 00110000
54 | }
55 |
56 | unit_code = {
57 | 0: 0x0000, # 00000000 00000000
58 | 1: 0x0000, # 00000000 00000000
59 | 2: 0x0010, # 00000000 00010000
60 | 3: 0x0008, # 00000000 00001000
61 | 4: 0x0018, # 00000000 00011000
62 | 5: 0x0040, # 00000000 01000000
63 | 6: 0x0050, # 00000000 01010000
64 | 7: 0x0048, # 00000000 01001000
65 | 8: 0x0058, # 00000000 01011000
66 | 9: 0x0400, # 00000100 00000000
67 | 10: 0x0410, # 00000100 00010000
68 | 11: 0x0408, # 00000100 00001000
69 | 12: 0x0400, # 00000100 00000000
70 | 13: 0x0440, # 00000100 01000000
71 | 14: 0x0450, # 00000100 01010000
72 | 15: 0x0448, # 00000100 01001000
73 | 16: 0x0458, # 00000100 01011000
74 | }
75 |
76 | cmd_code = {
77 | "ON": 0x00, # 00000000
78 | "OFF": 0x20, # 00100000
79 | "BRT": 0x88, # 10001000
80 | "DIM": 0x98, # 10011000
81 | "ALL-OFF": 0x80, # 10000000
82 | "ALL-ON": 0x91, # 10010001
83 | "ALL-LTS-OFF": 0x84, # 10000100
84 | "ALL-LTS-ON": 0x94, # 10010100
85 | # All lights on 0x90 10010000
86 | # All lights off 0xA0 10100000
87 | # All units off 0x80 10000000
88 | }
89 |
90 |
91 | # takes args for housecode unit and x10 command
92 | # and returns a string representing bits for X10 RF command
93 | #
94 | # Args: A 10 ON
95 | # returns 01100100100110110001000011101111
96 | #
97 | def gen_x10(targ_house, targ_unit, targ_cmd):
98 | res = [0, 0]
99 |
100 | if _debug:
101 | print(targ_house, targ_unit, targ_cmd, file=sys.stderr)
102 |
103 | res[0] = houseCodes[targ_house]
104 |
105 | if targ_unit and not cmd_code[targ_cmd] & 0x80:
106 | res[0] |= (unit_code[targ_unit] >> 8) & 0xFF
107 | res[1] |= unit_code[targ_unit] & 0xFF
108 |
109 | res[1] |= cmd_code[targ_cmd] & 0xFF
110 |
111 | if _debug:
112 | print(
113 | f"{res[0]:08b} {res[0]^0xff:08b} {res[1]:08b} {res[1]^0xff:08b}",
114 | file=sys.stderr,
115 | )
116 |
117 | return f"{res[0]:08b}{res[0]^0xff:08b}{res[1]:08b}{res[1]^0xff:08b}"
118 |
119 |
120 | # Takes a string representing binary bits
121 | # and generates Flipper SubGhz RAW File data
122 | def gen_subfile(pkt_bits, note="x10 command", repeat=1):
123 | datalines = []
124 | for bits in pkt_bits:
125 | data = [9000, -4500]
126 |
127 | for bit in bits:
128 | if bit == "1":
129 | data.extend((562, -1688))
130 | else:
131 | data.extend((562, -563))
132 |
133 | data.extend((562, -40000))
134 |
135 | for i in range(0, len(data), 510):
136 | batch = map(str, data[i: i + 510])
137 | datalines.append(f'RAW_Data: {" ".join(batch)}')
138 |
139 | bb = pkt_bits[0]
140 | bin_dat = " ".join([bb[i: i + 8] for i in range(0, len(bb), 8)])
141 |
142 | hdr = f"""Filetype: Flipper SubGhz RAW File
143 | Version: 1
144 | # {note} {bin_dat}
145 | # Generated with subghz_x10.py https://github.com/evilpete/flipper_toolbox
146 | # {time.ctime()}
147 | Frequency: {rf_freq}
148 | Preset: FuriHalSubGhzPresetOok650Async
149 | Protocol: RAW
150 | """
151 |
152 | res = hdr
153 |
154 | res += "\n".join(datalines) + "\n"
155 | if repeat > 1:
156 | for i in range(0, repeat):
157 | res += "\n".join(datalines) + "\n"
158 |
159 | return res
160 |
161 |
162 | #
163 | # Generates fikes for the commands
164 | # ALL-ON ALL-OFF ALL-LTS-ON ALL-LTS-OFF
165 | # for for every housecode
166 | #
167 | def gen_brute_all():
168 | cmd_off = []
169 | cmd_on = []
170 | cmd_lts_off = []
171 | cmd_lts_on = []
172 | for h in houseCodes:
173 | xoff = gen_x10(h, "", "ALL-OFF")
174 | cmd_off.append(xoff) # repeat 3 times
175 | cmd_off.append(xoff)
176 | cmd_off.append(xoff)
177 |
178 | xon = gen_x10(h, "", "ALL-ON")
179 | cmd_on.append(xon) # repeat 3 times
180 | cmd_on.append(xon)
181 | cmd_on.append(xon)
182 |
183 | xloff = gen_x10(h, "", "ALL-LTS-OFF")
184 | cmd_lts_off.append(xloff) # repeat 3 times
185 | cmd_lts_off.append(xloff)
186 | cmd_lts_off.append(xloff)
187 |
188 | xlon = gen_x10(h, "", "ALL-LTS-ON")
189 | cmd_lts_on.append(xlon) # repeat 3 times
190 | cmd_lts_on.append(xlon)
191 | cmd_lts_on.append(xlon)
192 |
193 | if _debug > 2:
194 | print("cmd_off", cmd_off)
195 |
196 | filenam = "X10_All-OFF"
197 | xdata = gen_subfile(cmd_off, note=filenam, repeat=1)
198 | with open(filenam + ".sub", "w", encoding="utf-8") as fdd:
199 | print(xdata, file=fdd)
200 |
201 | if _debug > 2:
202 | print("cmd_on", cmd_on)
203 |
204 | filenam = "X10_All-ON"
205 | xdata = gen_subfile(cmd_on, note=filenam, repeat=1)
206 | with open(filenam + ".sub", "w", encoding="utf-8") as fdd:
207 | print(xdata, file=fdd)
208 |
209 | filenam = "X10_All-LIGHTS-OFF"
210 | xdata = gen_subfile(cmd_lts_off, note=filenam, repeat=1)
211 | with open(filenam + ".sub", "w", encoding="utf-8") as fdd:
212 | print(xdata, file=fdd)
213 |
214 | filenam = "X10_All-LIGHTS-ON"
215 | xdata = gen_subfile(cmd_lts_on, note=filenam, repeat=1)
216 | with open(filenam + ".sub", "w", encoding="utf-8") as fdd:
217 | print(xdata, file=fdd)
218 |
219 |
220 | if __name__ == "__main__":
221 | args = sys.argv[1:]
222 |
223 | options = (
224 | "Valid options:\n"
225 | + "\tsubghz_x10.py [unit] \n"
226 | + "or\n"
227 | + "\tsubghz_x10.py -b"
228 | )
229 |
230 | if args and args[0][0] == "-":
231 | if args[0] == "-b":
232 | gen_brute_all()
233 | sys.exit()
234 | else:
235 | print("unlknown arg {args[0]}")
236 | print(options)
237 |
238 | if len(args) < 2:
239 | print("requires 2 or more args")
240 | sys.exit()
241 |
242 | node_targ = args.pop(0).upper()
243 | node_house = node_targ[0]
244 | node_unit = node_targ[1:]
245 | node_cmd = args.pop(0).upper()
246 |
247 | if node_cmd in cmd_code:
248 | pass
249 | elif node_cmd == "BRIGHT":
250 | node_cmd = "BRT"
251 | elif node_cmd in ["ALL_OFF", "ALLOFF"]:
252 | node_cmd = "ALL-OFF"
253 | elif node_cmd in ["ALL_ON", "ALLON"]:
254 | node_cmd = "ALL-ON"
255 | else:
256 | print("Unknown command code:", node_cmd)
257 | print("\tValid command are:", " ".join(cmd_code))
258 | print(options)
259 | sys.exit()
260 |
261 | if not (node_house and node_house in houseCodes):
262 | print("Unknown House code:", node_house)
263 | sys.exit()
264 |
265 | if not node_unit:
266 | node_unit = 0
267 | elif node_unit.isdigit():
268 | node_unit = int(node_unit)
269 | else:
270 | print("Invalid House unit:", node_unit)
271 | sys.exit()
272 |
273 | if int(node_unit) > 16:
274 | print("Invalid House unit:", node_house)
275 | print("\tValid values are 1 -> 16")
276 | sys.exit()
277 |
278 | # rr = gen_x10(node_house, node_unit, node_cmd)
279 | # pkt_data = f"{rr[0]:08b}{rr[0]^0xff:08b}{rr[1]:08b}{rr[1]^0xff:08b}"
280 |
281 | pkt_data = []
282 | if node_cmd in ["ON", "OFF"]:
283 | pkt_data.append(gen_x10(node_house, node_unit, node_cmd))
284 | pkt_data += pkt_data * 3
285 | elif node_cmd in ["BRT", "DIM"]:
286 | if node_unit:
287 | pkt_data.append(gen_x10(node_house, node_unit, "ON"))
288 | pkt_data += pkt_data * 2
289 | pkt_data.append(gen_x10(node_house, None, node_cmd))
290 | elif node_cmd.startswith("ALL"):
291 | node_unit = None
292 | pkt_data.append(gen_x10(node_house, None, node_cmd))
293 | pkt_data += pkt_data * 3
294 | else: # should never get here..
295 | print("Unknown command code:", node_cmd)
296 |
297 | if _debug:
298 | print(node_house, node_unit, node_cmd, file=sys.stderr)
299 |
300 | while args:
301 | node_cmd = args.pop(0).upper()
302 | if node_cmd in ["BRT", "DIM"]:
303 | pkt_data.append(gen_x10(node_house, None, node_cmd))
304 | else:
305 | print("Skipping unknown command code:", node_cmd)
306 |
307 | if _debug:
308 | print("pkt_data", pkt_data, file=sys.stderr)
309 |
310 | if node_unit:
311 | filen = f"{node_house}{node_unit:02d}_{node_cmd}"
312 | else:
313 | filen = f"{node_house}_{node_cmd}"
314 |
315 | fdata = gen_subfile(pkt_data, note=filen)
316 |
317 | with open(filen + ".sub", "w", encoding="utf-8") as fd:
318 | print(fdata, file=fd)
319 |
320 | sys.exit()
321 |
--------------------------------------------------------------------------------
/test_dat/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | test / example data
4 |
--------------------------------------------------------------------------------
/test_dat/Raw_Sample.sub:
--------------------------------------------------------------------------------
1 | Filetype: Flipper SubGhz RAW File
2 | Version: 1
3 | Frequency: 433920000
4 | Preset: FuriHalSubGhzPresetCustom
5 | Custom_preset_module: CC1101
6 | Custom_preset_data: 02 0D 03 07 08 32 0B 06 14 00 13 00 12 30 11 32 10 17 18 18 19 18 1D 91 1C 00 1B 07 20 FB 22 11 21 B6 00 00 00 C0 00 00 00 00 00 00
7 | Protocol: RAW
8 | RAW_Data: 25749 -66 16643 -66 52101 -66 76071 -66 25167 -100 3523 -68 12817 -100 1683 -66 13137 -68 16063 -66 12073 -66 1225 -68 14891 -66 14073 -100 30201 -100 1331 -66 23949 -134 2093 -66 25929 -66 927 -66 19875 -66 2099 -100 51515 -98 461 -100 36315 -66 24583 -100 1327 -66 3285 -68 62649 -100 5965 -66 33455 -66 14825 -98 4761 -98 3455 -66 11409 -66 35341 -66 17017 -66 5291 -66 5103 -66 85611 -66 11361 -66 12913 -68 62157 -64 3375 -66 15693 -66 1499 -66 5347 -66 53579 -130 14549 -66 3417 -66 21197 -66 40323 -66 73109 -66 863 -66 3703 -100 23373 -66 49749 -66 4099 -66 84557 -66 104659 -98 51665 -66 106069 -66 65621 -66 11589 -100 155751 -98 22469 -66 14561 -66 96457
9 |
--------------------------------------------------------------------------------
/test_dat/mf-classic-1k-23AD7C86.json:
--------------------------------------------------------------------------------
1 | {
2 | "Created": "proxmark3",
3 | "FileType": "mfcard",
4 | "Card": {
5 | "UID": "23AD7C86",
6 | "ATQA": "0400",
7 | "SAK": "08"
8 | },
9 | "blocks": {
10 | "0": "23AD7C86740804006263646566676869",
11 | "1": "0AC08556F8106609A1C3B0BD30ADD9F0",
12 | "2": "52000400000000000000000000000000",
13 | "3": "A1670589B2AFFF078069FFFFFFFFFFFF",
14 | "4": "2200020000000000000000C10000001E",
15 | "5": "2200020000000000000000C10000001E",
16 | "6": "00000000000000000000000000000000",
17 | "7": "2A2C13CC242AFF078069FFFFFFFFFFFF",
18 | "8": "00000000000000000000000000000000",
19 | "9": "00000000000000000000000000000000",
20 | "10": "00000000000000000000000000000000",
21 | "11": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
22 | "12": "00000000000000000000000000000000",
23 | "13": "00000000000000000000000000000000",
24 | "14": "00000000000000000000000000000000",
25 | "15": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
26 | "16": "A2658DB4203A00A2A2659201203A00F4",
27 | "17": "A2655B9D202D004CA2755C00201F00B2",
28 | "18": "A2655C02202D00B2A2655C07202D00B7",
29 | "19": "A1670589B2AFFF078069FFFFFFFFFFFF",
30 | "20": "A2655D2F202D00E0A265600220DE0067",
31 | "21": "A2656002202D00B6A265619920DE00FF",
32 | "22": "A265619D202D0052A26561AB202D0060",
33 | "23": "A1670589B2AFFF078069FFFFFFFFFFFF",
34 | "24": "A2657D5A202D002BA26581B3202D0088",
35 | "25": "A2651BC820CC00D6A2651C8F20CC009E",
36 | "26": "00000000000000000000000000000000",
37 | "27": "A1670589B2AF00000000FFFFFFFFFFFF",
38 | "28": "00000000000000000000000000000000",
39 | "29": "00000000000000000000000000000000",
40 | "30": "00000000000000000000000000000000",
41 | "31": "A1670589B2AF00000000FFFFFFFFFFFF",
42 | "32": "00000000000000000000000000000000",
43 | "33": "00000000000000000000000000000000",
44 | "34": "00000000000000000000000000000000",
45 | "35": "A1670589B2AF00000000FFFFFFFFFFFF",
46 | "36": "00000000000000000000000000000000",
47 | "37": "00000000000000000000000000000000",
48 | "38": "00000000000000000000000000000000",
49 | "39": "A1670589B2AF00000000FFFFFFFFFFFF",
50 | "40": "00000000000000000000000000000000",
51 | "41": "00000000000000000000000000000000",
52 | "42": "00000000000000000000000000000000",
53 | "43": "A1670589B2AF00000000FFFFFFFFFFFF",
54 | "44": "00000000000000000000000000000000",
55 | "45": "00000000000000000000000000000000",
56 | "46": "00000000000000000000000000000000",
57 | "47": "A1670589B2AF00000000FFFFFFFFFFFF",
58 | "48": "00000000000000000000000000000000",
59 | "49": "00000000000000000000000000000000",
60 | "50": "00000000000000000000000000000000",
61 | "51": "A1670589B2AF00000000FFFFFFFFFFFF",
62 | "52": "00000000000000000000000000000000",
63 | "53": "00000000000000000000000000000000",
64 | "54": "00000000000000000000000000000000",
65 | "55": "A1670589B2AF00000000FFFFFFFFFFFF",
66 | "56": "00000000000000000000000000000000",
67 | "57": "00000000000000000000000000000000",
68 | "58": "00000000000000000000000000000000",
69 | "59": "A1670589B2AF00000000FFFFFFFFFFFF",
70 | "60": "00000000000000000000000000000000",
71 | "61": "00000000000000000000000000000000",
72 | "62": "00000000000000000000000000000000",
73 | "63": "A1670589B2AF0400468EFFFFFFFFFFFF"
74 | },
75 | "SectorKeys": {
76 | "0": {
77 | "KeyA": "A1670589B2AF",
78 | "KeyB": "FFFFFFFFFFFF",
79 | "AccessConditions": "FF078069",
80 | "AccessConditionsText": {
81 | "block0": "read AB; write AB; increment AB; decrement transfer restore AB",
82 | "block1": "read AB; write AB; increment AB; decrement transfer restore AB",
83 | "block2": "read AB; write AB; increment AB; decrement transfer restore AB",
84 | "block3": "write A by A; read/write ACCESS by A; read/write B by A",
85 | "UserData": "69"
86 | }
87 | },
88 | "1": {
89 | "KeyA": "2A2C13CC242A",
90 | "KeyB": "FFFFFFFFFFFF",
91 | "AccessConditions": "FF078069",
92 | "AccessConditionsText": {
93 | "block4": "read AB; write AB; increment AB; decrement transfer restore AB",
94 | "block5": "read AB; write AB; increment AB; decrement transfer restore AB",
95 | "block6": "read AB; write AB; increment AB; decrement transfer restore AB",
96 | "block7": "write A by A; read/write ACCESS by A; read/write B by A",
97 | "UserData": "69"
98 | }
99 | },
100 | "2": {
101 | "KeyA": "FFFFFFFFFFFF",
102 | "KeyB": "FFFFFFFFFFFF",
103 | "AccessConditions": "FF078069",
104 | "AccessConditionsText": {
105 | "block8": "read AB; write AB; increment AB; decrement transfer restore AB",
106 | "block9": "read AB; write AB; increment AB; decrement transfer restore AB",
107 | "block10": "read AB; write AB; increment AB; decrement transfer restore AB",
108 | "block11": "write A by A; read/write ACCESS by A; read/write B by A",
109 | "UserData": "69"
110 | }
111 | },
112 | "3": {
113 | "KeyA": "FFFFFFFFFFFF",
114 | "KeyB": "FFFFFFFFFFFF",
115 | "AccessConditions": "FF078069",
116 | "AccessConditionsText": {
117 | "block12": "read AB; write AB; increment AB; decrement transfer restore AB",
118 | "block13": "read AB; write AB; increment AB; decrement transfer restore AB",
119 | "block14": "read AB; write AB; increment AB; decrement transfer restore AB",
120 | "block15": "write A by A; read/write ACCESS by A; read/write B by A",
121 | "UserData": "69"
122 | }
123 | },
124 | "4": {
125 | "KeyA": "A1670589B2AF",
126 | "KeyB": "FFFFFFFFFFFF",
127 | "AccessConditions": "FF078069",
128 | "AccessConditionsText": {
129 | "block16": "read AB; write AB; increment AB; decrement transfer restore AB",
130 | "block17": "read AB; write AB; increment AB; decrement transfer restore AB",
131 | "block18": "read AB; write AB; increment AB; decrement transfer restore AB",
132 | "block19": "write A by A; read/write ACCESS by A; read/write B by A",
133 | "UserData": "69"
134 | }
135 | },
136 | "5": {
137 | "KeyA": "A1670589B2AF",
138 | "KeyB": "FFFFFFFFFFFF",
139 | "AccessConditions": "FF078069",
140 | "AccessConditionsText": {
141 | "block20": "read AB; write AB; increment AB; decrement transfer restore AB",
142 | "block21": "read AB; write AB; increment AB; decrement transfer restore AB",
143 | "block22": "read AB; write AB; increment AB; decrement transfer restore AB",
144 | "block23": "write A by A; read/write ACCESS by A; read/write B by A",
145 | "UserData": "69"
146 | }
147 | },
148 | "6": {
149 | "KeyA": "A1670589B2AF",
150 | "KeyB": "FFFFFFFFFFFF",
151 | "AccessConditions": "00000000",
152 | "AccessConditionsText": {
153 | "block24": "read AB; write AB; increment AB; decrement transfer restore AB",
154 | "block25": "read AB; write AB; increment AB; decrement transfer restore AB",
155 | "block26": "read AB; write AB; increment AB; decrement transfer restore AB",
156 | "block27": "read A by A; read ACCESS by A; read/write B by A",
157 | "UserData": "00"
158 | }
159 | },
160 | "7": {
161 | "KeyA": "A1670589B2AF",
162 | "KeyB": "FFFFFFFFFFFF",
163 | "AccessConditions": "00000000",
164 | "AccessConditionsText": {
165 | "block28": "read AB; write AB; increment AB; decrement transfer restore AB",
166 | "block29": "read AB; write AB; increment AB; decrement transfer restore AB",
167 | "block30": "read AB; write AB; increment AB; decrement transfer restore AB",
168 | "block31": "read A by A; read ACCESS by A; read/write B by A",
169 | "UserData": "00"
170 | }
171 | },
172 | "8": {
173 | "KeyA": "A1670589B2AF",
174 | "KeyB": "FFFFFFFFFFFF",
175 | "AccessConditions": "00000000",
176 | "AccessConditionsText": {
177 | "block32": "read AB; write AB; increment AB; decrement transfer restore AB",
178 | "block33": "read AB; write AB; increment AB; decrement transfer restore AB",
179 | "block34": "read AB; write AB; increment AB; decrement transfer restore AB",
180 | "block35": "read A by A; read ACCESS by A; read/write B by A",
181 | "UserData": "00"
182 | }
183 | },
184 | "9": {
185 | "KeyA": "A1670589B2AF",
186 | "KeyB": "FFFFFFFFFFFF",
187 | "AccessConditions": "00000000",
188 | "AccessConditionsText": {
189 | "block36": "read AB; write AB; increment AB; decrement transfer restore AB",
190 | "block37": "read AB; write AB; increment AB; decrement transfer restore AB",
191 | "block38": "read AB; write AB; increment AB; decrement transfer restore AB",
192 | "block39": "read A by A; read ACCESS by A; read/write B by A",
193 | "UserData": "00"
194 | }
195 | },
196 | "10": {
197 | "KeyA": "A1670589B2AF",
198 | "KeyB": "FFFFFFFFFFFF",
199 | "AccessConditions": "00000000",
200 | "AccessConditionsText": {
201 | "block40": "read AB; write AB; increment AB; decrement transfer restore AB",
202 | "block41": "read AB; write AB; increment AB; decrement transfer restore AB",
203 | "block42": "read AB; write AB; increment AB; decrement transfer restore AB",
204 | "block43": "read A by A; read ACCESS by A; read/write B by A",
205 | "UserData": "00"
206 | }
207 | },
208 | "11": {
209 | "KeyA": "A1670589B2AF",
210 | "KeyB": "FFFFFFFFFFFF",
211 | "AccessConditions": "00000000",
212 | "AccessConditionsText": {
213 | "block44": "read AB; write AB; increment AB; decrement transfer restore AB",
214 | "block45": "read AB; write AB; increment AB; decrement transfer restore AB",
215 | "block46": "read AB; write AB; increment AB; decrement transfer restore AB",
216 | "block47": "read A by A; read ACCESS by A; read/write B by A",
217 | "UserData": "00"
218 | }
219 | },
220 | "12": {
221 | "KeyA": "A1670589B2AF",
222 | "KeyB": "FFFFFFFFFFFF",
223 | "AccessConditions": "00000000",
224 | "AccessConditionsText": {
225 | "block48": "read AB; write AB; increment AB; decrement transfer restore AB",
226 | "block49": "read AB; write AB; increment AB; decrement transfer restore AB",
227 | "block50": "read AB; write AB; increment AB; decrement transfer restore AB",
228 | "block51": "read A by A; read ACCESS by A; read/write B by A",
229 | "UserData": "00"
230 | }
231 | },
232 | "13": {
233 | "KeyA": "A1670589B2AF",
234 | "KeyB": "FFFFFFFFFFFF",
235 | "AccessConditions": "00000000",
236 | "AccessConditionsText": {
237 | "block52": "read AB; write AB; increment AB; decrement transfer restore AB",
238 | "block53": "read AB; write AB; increment AB; decrement transfer restore AB",
239 | "block54": "read AB; write AB; increment AB; decrement transfer restore AB",
240 | "block55": "read A by A; read ACCESS by A; read/write B by A",
241 | "UserData": "00"
242 | }
243 | },
244 | "14": {
245 | "KeyA": "A1670589B2AF",
246 | "KeyB": "FFFFFFFFFFFF",
247 | "AccessConditions": "00000000",
248 | "AccessConditionsText": {
249 | "block56": "read AB; write AB; increment AB; decrement transfer restore AB",
250 | "block57": "read AB; write AB; increment AB; decrement transfer restore AB",
251 | "block58": "read AB; write AB; increment AB; decrement transfer restore AB",
252 | "block59": "read A by A; read ACCESS by A; read/write B by A",
253 | "UserData": "00"
254 | }
255 | },
256 | "15": {
257 | "KeyA": "A1670589B2AF",
258 | "KeyB": "FFFFFFFFFFFF",
259 | "AccessConditions": "0400468E",
260 | "AccessConditionsText": {
261 | "block60": "read AB; write AB; increment AB; decrement transfer restore AB",
262 | "block61": "read AB",
263 | "block62": "read B; write B",
264 | "block63": "read A by A; read ACCESS by A; read/write B by A",
265 | "UserData": "8E"
266 | }
267 | }
268 | }
269 | }
--------------------------------------------------------------------------------
/test_dat/setting_user:
--------------------------------------------------------------------------------
1 | Filetype: Flipper SubGhz Setting File
2 | Version: 1
3 |
4 | # Add All Standard frequencies
5 | #Add_standard_frequencies: true
6 |
7 | # Default Frequency: used as default for "Read" and "Read Raw"
8 | #Default_frequency: 433920000
9 |
10 | # Frequencies used for "Read", "Read Raw" and "Frequency Analyzer" - they added after default ones if enabled in Add_standard_frequencies
11 | Frequency: 302757000
12 | Frequency: 307000000
13 | Frequency: 307500000
14 | Frequency: 307800000
15 | Frequency: 309000000
16 | Frequency: 312000000
17 | Frequency: 312100000
18 | Frequency: 313850000
19 | Frequency: 314000000
20 | Frequency: 314350000
21 | Frequency: 345000000
22 | Frequency: 348000000
23 | Frequency: 387000000
24 | Frequency: 433220000
25 | Frequency: 433889000
26 | Frequency: 464000000
27 | Frequency: 779000000
28 | Frequency: 928000000
29 |
30 | # Frequencies used for hopping mode (keep this list small or flipper will miss signal) - they added after default ones if enabled in Add_standard_frequencies
31 | #Hopper_frequency: 300000000
32 | Hopper_frequency: 345000000
33 | Hopper_frequency: 434420000
34 |
35 | # Custom preset
36 | # format for CC1101 "Custom_preset_data:" XX YY XX YY .. 00 00 ZZ ZZ ZZ ZZ ZZ ZZ ZZ ZZ, where: XX-register, YY - register data, 00 00 - end load register, ZZ - 8 byte Pa table register
37 |
38 | #Custom_preset_name: AM_1
39 | #Custom_preset_module: CC1101
40 | #Custom_preset_data: 02 0D 03 07 08 32 0B 06 14 00 13 00 12 30 11 32 10 17 18 18 19 18 1D 91 1C 00 1B 07 20 FB 22 11 21 B6 00 00 00 C0 00 00 00 00 00 00
41 |
42 | #Custom_preset_name: AM_2
43 | #Custom_preset_module: CC1101
44 | #Custom_preset_data: 02 0D 03 07 08 32 0B 06 14 00 13 00 12 30 11 32 10 17 18 18 19 18 1D 91 1C 00 1B 07 20 FB 22 11 21 B6 00 00 00 C0 00 00 00 00 00 00
45 |
46 | ## Default presets as examples :
47 |
48 | # PresetOok270Async
49 | Custom_preset_name: AM270
50 | Custom_preset_module: CC1101
51 | Custom_preset_data: 02 0d 03 47 08 32 0b 06 14 00 13 00 12 30 11 32 10 67 18 18 19 18 1d 40 1c 00 1b 03 20 fb 22 11 21 b6 00 00 00 C0 00 00 00 00 00 00
52 |
53 | # PresetOok650Async
54 | Custom_preset_name: AM650
55 | Custom_preset_module: CC1101
56 | Custom_preset_data: 02 0d 03 07 08 32 0b 06 14 00 13 00 12 30 11 32 10 17 18 18 19 18 1d 91 1c 00 1b 07 20 fb 22 11 21 b6 00 00 00 C0 00 00 00 00 00 00
57 |
58 | # Preset2FSKDev238Async
59 | Custom_preset_name: FM238
60 | Custom_preset_module: CC1101
61 | Custom_preset_data: 02 0d 0b 06 08 32 07 04 14 00 13 02 12 04 11 83 10 67 15 04 18 18 19 16 1d 91 1c 00 1b 07 20 fb 22 10 21 56 00 00 C0 00 00 00 00 00 00 00
62 |
63 |
64 | # Preset2FSKDev476Async
65 | Custom_preset_name: FM476
66 | Custom_preset_module: CC1101
67 | Custom_preset_data: 02 0d 0b 06 08 32 07 04 14 00 13 02 12 04 11 83 10 67 15 47 18 18 19 16 1d 91 1c 00 1b 07 20 fb 22 10 21 56 00 00 C0 00 00 00 00 00 00 00
68 |
69 |
70 | # PresetMSK99_97KbAsync
71 | Custom_preset_name: MSK99_9
72 | Custom_preset_module: CC1101
73 | Custom_preset_data: 02 06 03 07 04 46 05 4c 09 00 06 00 0a 00 08 05 0c 23 0b 06 14 f8 13 22 12 72 11 f8 10 5b 15 47 18 18 19 16 1d b2 1c 00 1b c7 22 10 21 56 1a 1c 29 59 00 00 C0 00 00 00 00 00 00 00
74 |
75 |
76 | # PresetGFSK9_99KbAsync
77 | Custom_preset_name: GFSK9_99
78 | Custom_preset_module: CC1101
79 | Custom_preset_data: 02 06 03 47 08 05 0b 06 04 46 05 4c 09 00 06 00 10 c8 11 93 12 12 15 34 18 18 19 16 1b 43 1c 40 1d 91 20 fb 00 00 C0 00 00 00 00 00 00 00
80 |
--------------------------------------------------------------------------------
/url2flipnfc.py:
--------------------------------------------------------------------------------
1 | def procesar_url(url):
2 | """
3 | Procesa la URL para generar su representación en formato NDEF.
4 | """
5 | # Mapear protocolos a identificadores
6 | protocols = {
7 | "https://www.": "02", "http://www.": "01",
8 | "https://": "04", "http://": "03",
9 | "tel:": "05", "mailto:": "06"
10 | }
11 |
12 | # Identificar el protocolo y calcular el contenido restante
13 | uri_identifier = next((id for proto, id in protocols.items() if url.startswith(proto)), "00")
14 | resto = url.split("://")[-1] if "://" in url else url
15 | resto_hex = ''.join(format(byte, '02X') for byte in resto.encode('utf-8'))
16 |
17 | # Construir el mensaje NDEF
18 | longitud_resto = len(resto) + 1
19 | return f"D1 01 {longitud_resto:02X} 55 {uri_identifier} {resto_hex}"
20 |
21 |
22 | def dividir_en_filas(hex_string, longitud_fila=32):
23 | """
24 | Divide una cadena hexadecimal en filas de una longitud fija.
25 | """
26 | bytes_separados = [hex_string[i:i+2] for i in range(0, len(hex_string), 2)]
27 | return [
28 | ' '.join(bytes_separados[i:i + (longitud_fila // 2)])
29 | for i in range(0, len(bytes_separados), longitud_fila // 2)
30 | ]
31 |
32 |
33 | def ajustar_bloques(filas, bloque_inicial=4):
34 | """
35 | Ajusta las filas para que sean múltiplos de 4, agrega relleno y numera los bloques.
36 | """
37 | # Rellenar filas individuales para que tengan 16 bytes (32 caracteres)
38 | filas_rellenas = [fila.ljust(47, ' ') + "00 " * ((32 - len(fila.replace(' ', '')) // 2)) for fila in filas]
39 |
40 | # Calcular cuántas filas faltan para completar un múltiplo de 4
41 | filas_faltantes = (4 - len(filas_rellenas) % 4) % 4
42 | filas_rellenas.extend(["00 " * 16] * filas_faltantes)
43 |
44 | # Numerar los bloques
45 | return [f"Block {bloque_inicial + i}: {fila}" for i, fila in enumerate(filas_rellenas)]
46 |
47 |
48 | def generar_archivo_flipper(url, uid="1E 0A 23 3F"):
49 | """
50 | Genera un archivo compatible con Flipper para una URL dada.
51 | """
52 | contenido_ndef = procesar_url(url)
53 | mensaje_completo = f"03 {len(contenido_ndef.split()):02X} {contenido_ndef} FE"
54 | filas = dividir_en_filas(mensaje_completo)
55 | bloques_numerados = ajustar_bloques(filas, bloque_inicial=4)
56 |
57 | # Cabecera del archivo
58 | cabecera = f"""
59 | Filetype: Flipper NFC device
60 | Version: 4
61 | Device type: Mifare Classic
62 | UID: {uid}
63 | ATQA: 00 04
64 | SAK: 08
65 | Mifare Classic type: 1K
66 | Data format version: 2
67 | """
68 | return cabecera + '\n'.join(bloques_numerados)
69 |
70 |
71 | # Ejemplo de uso
72 | url = input("Introduce la URL: ")
73 | archivo_flipper = generar_archivo_flipper(url)
74 |
75 | # Mostrar el contenido generado
76 | print("=== Archivo NFC generado ===")
77 | print(archivo_flipper)
78 |
--------------------------------------------------------------------------------