{"id":31588477,"url":"https://github.com/smeso/esp32-ptm216b","last_synced_at":"2026-05-07T05:39:23.533Z","repository":{"id":317735132,"uuid":"1066573469","full_name":"smeso/esp32-ptm216b","owner":"smeso","description":"Replacement FW for Sonoff's MINIR4 to be able to control it directly with Enocean's PTM216B module. It can also run on any ESP32 board. The repo also includes a script that can run on Linux to receive actions from the PTM216B.","archived":false,"fork":false,"pushed_at":"2025-10-02T17:13:29.000Z","size":3966,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-02T19:13:04.193Z","etag":null,"topics":["ble","enocean","esp32","linux","nfc","ota","ota-update","ptm216b","raspberry-pi","smart-lights","smarthome","smartlighting","sonoff"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/smeso.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-29T17:08:22.000Z","updated_at":"2025-10-02T17:13:32.000Z","dependencies_parsed_at":"2025-10-02T19:13:38.070Z","dependency_job_id":"3225a3c6-3527-4523-983e-c634e5c654ac","html_url":"https://github.com/smeso/esp32-ptm216b","commit_stats":null,"previous_names":["smeso/esp32-ptm216b"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/smeso/esp32-ptm216b","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smeso%2Fesp32-ptm216b","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smeso%2Fesp32-ptm216b/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smeso%2Fesp32-ptm216b/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smeso%2Fesp32-ptm216b/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smeso","download_url":"https://codeload.github.com/smeso/esp32-ptm216b/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smeso%2Fesp32-ptm216b/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278547821,"owners_count":26004775,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ble","enocean","esp32","linux","nfc","ota","ota-update","ptm216b","raspberry-pi","smart-lights","smarthome","smartlighting","sonoff"],"created_at":"2025-10-06T02:09:49.721Z","updated_at":"2025-10-06T02:11:10.045Z","avatar_url":"https://github.com/smeso.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"Overview\n========\n\n![Demo of the PTM216B and the MINIR4 in action](pics/demo.gif)\n\nThis is a replacement firmware for the ESP32 powering\n[Sonoff's MINIR4](https://sonoff.tech/en-it/products/sonoff-mini-extreme-wi-fi-smart-switch-minir4)\nthat enables it to directly respond to actions from\n[Enocean's PTM216B](https://www.enocean.com/en/product/ptm-216b/).\n\n**MINIR4** is a ridiculously small 10A smart relay that can be used\nto retrofit an old lighting system. The MCU is an unlocked ESP32\n(specifically ESP32-D0WD-V3 revision v3.1) and you can upload any\ncustom firmware on it.\n\n**PTM216B** is a wireless module with 4 buttons that will send\nBLE messages whenever its button are pressed or released.\nIt doesn't need any external power or battery.\nIt is able to harvest all the energy that it needs from the\nbutton movement itself.\nEnocean also sells a ready to use encased unit. But the module can\nalso be found inside units made by other companies.\nMaybe the company that made your home light switches has a customized\nversion of this module that matches the style of the other switches\nthat you already have.\nI'm trying to compile a\n[list of such devices](#list-of-vendors-and-products-using-ptm216b).\n\nWith this firmware it's possible to control one or more MINIR4 from\none or more PTM216B, without any other device in the middle.\nThe latency between pressing a button on the PTM216B and the light being\nturned on is very short (less than 30ms) and it feels like the light\nturns on instantly.\n\nEven if this project was specifically developed for the MINIR4 it can\nrun on any device with an MCU of the ESP32 family.\n\n\n:skull_and_crossbones: **DISCLAIMER** :skull_and_crossbones:\n============================================================\n\nThis project is **NOT** officially supported and is **NOT**\nendorsed by Espressif, Sonoff or Enocean.\n\nThe *Sonoff MINIR4* is a device that works with\n**mains electricity**: tampering with it, in any way, can\nbe **deadly dangerous**.\nThe instructions and the software in this repository should only be\nused by **experts** at their own risk.\nNEVER open the case or touch anything inside it while the device is\nplugged to mains and, even when unplugged, great caution must be\nexercised around the capacitors that might still have charge.\nBe aware that the 3v3 pins of the ESP32 in the *Sonoff MINI R4* are\n3v3 when referenced to each other, but they are actually 100/240 V\nwhen referenced to earth (or your body).\n\nRemember that *Sonoff MINI R4* is rated for **10A max**\nloads. Do NOT try to drive higher loads.\n\nIf some of the information in this disclaimer is unclear or you are\nnot confident about its meaning or implications, it may be too\ndangerous for you to use this project.\nMaybe you can find someone near you with more experience that\ncan help you to use it safely. It might be a good excuse to find out\nabout your local hackerspace!\n\n\nDevice configuration\n====================\n\nThe device configuration (e.g. keys, addresses, actions to perform) is\nstored in the `devices.json` file. By default the build system will look for\nthis file in the project root, but the path and the file name\ncan be customized using `idf.py menuconfig`.\nThe structure of this file should follow the example in\n[devices.json.example](devices.json.example).\nHopefully the example is self-explanatory.\n\nBy default, `Resolvable Private Address (rpa)` and `encryption` are disabled in the PTM216B.\nThe BLE address and the key can be obtained from the QR code that should be on the\nback of the module, see\n[Section 8.2 in PTM216B's doc](https://www.enocean.com/wp-content/uploads/downloads-produkte/en/products/enocean_modules_24ghz_ble/ptm-216b/PTM-216B-User-Manual.pdf).\nAlternatively you can read them via [NFC](#nfc-configuration-of-ptm216b).\nPlease remember that when you enable encryption the BLE address will change.\n\n\u003e [!NOTE]\n\u003e Remember to add a combo to enter OTA mode! (if you use OTA updates)\n\n\nReceiving PTM216B messages from Linux\n=====================================\n\nIn `tools/linux_recv` there is a small script for Linux (it may work on other\nplatforms too) that can receive messages from PTM216B via BLE.\nIt uses the same `device.json` file used by this FW and, like this FW,\nsupports both encryption and RPA. It doesn't implement more advanced features\n(provided by this FW) like persisting the counters or bruteforce prevention.\n\nIt can be used for tests or to drive a RasperryPi or a Linux laptop using a\nPTM216B.\n\n\nOTA updates\n===========\n\nThe firmware supports OTA updates using BLE.\nOTA updates are disabled by default, because you need to generate a key and set a\npassword to be able to compile the FW with it.\nBut **you are strongly encouraged to enable it**, because flashing the MINIR4 via\nUART is very impractical, especially after it's installed in an electrical box.\n\nBefore being able to perform an OTA update, the MINIR4 need to enter \"OTA mode\".\nIn this mode it won't be able to receive commands from any PTM216B anymore, but you\nwill still be able to use the push button and the switch attached to SW2 to\nturn the light on and off.\n\nThere is an option (which is OFF by default) to be able to enter OTA mode pressing\nthe push button on the MINIR4 for 10 seconds.\n\nPTM216B buttons can also be used to enter OTA, this should probably be the\npreferred way to enter OTA mode, as it doesn't require physical access to the\nMINIR4 at all.\nIdeally you should use long press of a combination that is unlikely to happen\naccidentally e.g. buttons A0+B1 or even A0+A1+B0+B1 (many finished units use\nrocker buttons that make it impossible to press all 4 buttons at the same time,\nbut the PTM216B supports pressing all of them and you can do so by simply\ndisassembling the rocker buttons).\n\nIf you have more than one MINIR4 it's better to use different sequences to control\nOTA mode, because if more than one device enters OTA mode there is no way to\ncontrol which one will be updated (a fix for this is in my [TODO](#TODO) list).\n\nIf you enter OTA mode accidentally, don't worry, MINIR4 will exit the mode\nautomatically after 1 minute of inactivity.\n\nThe updates are performed using an active/inactive partition system and if the\nupload fails for whatever reason (e.g. power outage, FW corruption etc) the\nMINIR4 will keep using the old FW without issues.\n\nTo perform an OTA update you will need to run `tools/ota/ota.py`.\nThis tool is based on Espressif's\n[esp_prov](https://github.com/espressif/esp-idf/tree/master/tools/esp_prov).\nIt was tested only on Linux, it may work on other OS's too, but why would\nyou use another OS?\n`ota.py` depends on [bleak](https://pypi.org/project/bleak/) and\n[cryptography](https://pypi.org/project/cryptography/).\n\n\n#### OTA updates security\n\nThe transfer is performed using the Espressif's `protocomm` in security mode 2\non top of BLE.\n\nBasically the authentication is performed using\n[SRP6a key-exchange](https://datatracker.ietf.org/doc/html/rfc5054)\nand then the\ndata is encrypted and authenticated using\n[AES-GCM](https://en.wikipedia.org/wiki/Galois/Counter_Mode).\nFor more details about how it works you can read\n[ESP-IDF's doc](https://docs.espressif.com/projects/esp-idf/en/v5.4.2/esp32/api-reference/provisioning/provisioning.html#security-2-scheme).\n\nTo further strengthen `protocomm`, instead of using the plain, user-provided,\npassword with SRP we pass it through a few rounds of\n[Scrypt](https://en.wikipedia.org/wiki/Scrypt)\nso that the `verifier blob` embedded in the FW image is more brute-force resistant.\n\nThe uploaded FW should also be signed using an RSA key, the `ota.py` utility can\ndo this on the fly or you can do it beforehand (e.g. if you keep the key on an\nair gapped machine). This feature has nothing to do with ESP's Secure Boot.\n\n#### How to enable OTA\n\nThe easiest way is to use `idf.py menuconfig`, you will find the option in the\n`ESP32-PTM216B` menu that is in the root menu.\nYou will also need to set a password via the dedicated option.\nIf you enable OTA and leave the password empty the FW compilation will fail.\nThe password is needed to secure your board and prevent malicious actors from\nswapping your FW, or sniffing your uploads, pick a good one!\nIf you lose your password you won't be able to use OTA updates anymore.\nIf you enabled ESP32's lockdown features properly (Secure Boot etc), OTA updates\nare the only way to change the FW (well, there is another way, but it's easier\nto buy a new MINIR4).\n\nTo generate the RSA key you need to run these commands:\n\n```\n$ cd keys\n$ ../tools/ota/ota.py generate-keys\n```\n\noptionally you can use `--key-password` to specify an encryption\npassword for the private key and `--key-size` to specify a size\n(by default it's 2048).\n\nNow you are all set and you can [build the FW](#build-the-firmware).\n\n\n#### How to use OTA updates\n\nEnter OTA mode with your preferred button combo and then run:\n\n```\n./ota.py update -f build/esp32-ptm216b.bin\n```\n\nYou will be prompted for the password configured via `menuconfig`\nand, if you decided to encrypt you secret RSA key, you will\nbe prompted for key password as well.\n\nBluez may show you a prompt to accept the connection to a BLE\ndevice named \"OTA\", of course you need to approve it.\n\nSometimes the connection fails, in that case it will be automatically\nretried up to 3 times (bluez may require you to manually approve each\nconnection).\nOnce the FW upload starts you will be able to see its progress.\nThe upload should take 4-5 minutes, be patient.\nOnce the upload is complete you will be asked to use again\na combo to enter OTA mode, you have 2 minutes to do so.\nIf you don't do it, the new FW will be discarded and the MINIR4 will\nrestart. This is necessary to make sure that the new FW is working\nand that you will be able to re-enter OTA in the future using the\nnew FW.\n\n#### How to create a detached signature for OTA\n\nTo create a detached signature you need to run\n\n```\n./tools/ota/ota.py sign \u003cfile-to-sign\u003e\n```\nYou will be prompted for the key password, if necessary.\nThe signature will be create as `\u003cfile-to-sign\u003e.sig`, if\nthe file already exists you will get an error.\n\nTo use the detached signature during a FW update you need to use\nthe `--load-sign` option:\n\n```\n./ota.py update -f build/esp32-ptm216b.bin --load-sign build/esp32-ptm216b.bin.sig\n```\n\n#### How to exit OTA mode immediately\n\nIf you changed your mind and you want to exit OTA mode without\nwaiting for 1 minute, you can do so running:\n\n```\n./tools/ota/ota.py reset-board\n```\n\nThis command restarts the MINIR4, it only works while in OTA mode.\n\n\nBuild the firmware\n==================\n\nFirst of all you need to create your [devices.json](#device-configuration)\nfile.\nThen enable [OTA updates](#how-to-enable-ota) (if you want to).\nFinally, you can compile the FW just like any other ESP32 FW:\n\n```\nidf.py -DIDF_TARGET=esp32 build\n```\n\nUsing ESP-IDF v5.5.1 and above is recommended.\n\n\nFlashing the firmware\n=====================\n\nThe ESP32 inside the MINIR4 is unlocked, so you can replace the FW on it\nsimply using the UART download mode.\nUnfortunately, to access its UART some soldering is required and the pads\nare very small and close to each other.\n\n#### Accessing the UART\n\n\u003e [!WARNING]\n\u003e Make sure that the device is unplugged! The 3v3 pad is **NOT** at 3.3 V\n\u003e when the device is plugged. Its voltage will be close to mains (i.e. 100-240 V).\n\nThe MINIR4 case doesn't use screws or glue, to open it you just need to gently\npush the 2 halves apart. You can help yourself using a plastic pry tool.\nAfter you opened the case, you should also remove the 2 pink thermal pads\nfrom the board.\nNow you can solder some wires on the pads indicated in the following pictures:\n\n![MINIR4 3v3 pads](pics/3v3.jpg)\n![MINIR4 UART pads](pics/uart.jpg)\n\nThe 3v3 pad has some coating on it, so you will have to scratch it a bit.\n\nNow you can connect the wires to your favourite serial-to-USB adapter.\nYou should be able to see some output from the MINIR4 using:\n\n```\nidf.py -DIDF_TARGET=esp32 -p /dev/ttyUSB0 monitor\n```\n\nOf course you may need to change `/dev/ttyUSB0` to something else depending\non your adapter.\n\n\u003e [!NOTE]\n\u003e When you will put everything back together, don't forget to put the thermal pads back\n\u003e too!\n\n#### Entering download mode\n\nEntering download mode is necessary to run all the commands in the following sections.\nTo do so, you need to hold down the button on the MINIR4 board (shown in the previous\npicture) while the device is booting.\n\n#### Downloading the original FW\n\nIf you want to save a copy the original FW before erasing it you can do so with:\n\n```\nesptool.py --port /dev/ttyUSB0 read_flash --flash_size 4MB 0 ALL flash.dump\n```\n\nOf course your serial adapter could appear as something other than `/dev/ttyUSB0`.\n\nThe original FW layout is:\n\n```text\nPartition Table:\n## Label           Usage          Type ST Offset   Length\n0 nvs              WiFi data        01 02 00009000 00010000\n1 reserve          WiFi data        01 02 00019000 00004000\n2 otadata          OTA data         01 00 0001d000 00002000\n3 phy_init         RF data          01 01 0001f000 00001000\n4 ota_0            OTA app          00 10 00020000 001f0000\n5 ota_1            OTA app          00 11 00210000 001f0000\n```\n\n#### Flash the new FW\n\nFirst of all erase the entire flash:\n```\nesptool.py --port /dev/ttyUSB0 erase_flash\n```\n\nand then flash the FW:\n\n```\nidf.py -DIDF_TARGET=esp32 flash\n```\n\nRemember to always manually re-enter download mode before each command.\n\n\nNFC configuration of PTM216B\n============================\n\nIt is possible to change some configuration options of PTM216B using NFC.\nEnocean provides some apps for\n[iOS](https://play.google.com/store/apps/details?id=de.enocean.easytool\u0026hl=en),\n[Android](https://play.google.com/store/apps/details?id=de.enocean.easytool\u0026hl=en),\nand [Windows](https://www.enocean.com/en/product/enocean-nfc-configurator/).\nThe mobile apps are a bit limited in what they can do, the Windows program\nis probably better, but I haven't tried it.\n\n`tools/nfc/nfc.py` is a small script that can be used to change\nsome configuration options for PTM216B.\nIt depends on [pyscard](https://pypi.org/project/pyscard/) and the\n[ACR122U](https://www.acs.com.hk/en/products/3/acr122u-usb-nfc-reader/)\nUSB NFC reader, which can be found very easily online and is quite cheap.\n\n`nfc.py` was only tested on Linux.\n\nIt doesn't support all configuration options that the PTM216B has.\nUnfortunately the public PTM216B doc doesn't say much about NFC.\n[Enocean has been kind enough](#credits) to share with me a small\npart of their non-public documentation, this allowed me to implement\nwhat you see in `nfc.py`.\n\nTo know what it can do, you can look at its `--help` or read the code.\n\n#### NFC security\n\nUsing `nfc.py` it is possible to change the NFC authentication password\nfrom the default value. This will prevent malicious actors from reading\nor changing PTM216B's parameters (e.g. encryption status and key).\nBe aware that if you change the password via `nfc.py` you won't be\nable to use Enocean's official software anymore, because they use a\nproprietary algorithm to generate the 4 bytes password from a 4 digit PIN,\nwhile `nfc.py` lets you set the password directly.\nIf you change the password from the default value and you forget it,\nthere is no way to recover it (well, maybe you can bruteforce it).\n\nThere is an anti-bruteforce feature that limits the number of failed\nattempts before the NFC interface is locked down forever.\nThis feature is disabled by default and, at the moment, `nfc.py`\ndoes not allow to enable it.\n\n\nSecurity\n========\n\n#### PTM216B's BLE\n\nThe BLE messages from PTM216B are authenticated using\n[AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) in\n[CCM mode](https://en.wikipedia.org/wiki/CCM_mode) with a 128 bit key that\nis different for each device.\nThe authentication tag size is only 4 bytes, so it can be bruteforced, but\nthis FW has [mitigations for that](#bruteforce-protection).\nTo prevent replay attacks, messages also contain a 32 bits counter that is\nincremented with every action. The FW [will ignore](#counter)\nmessages with old counter values.\n\nBy default the button status information is sent in plaintext, but it's possible\nto enable encryption via [NFC](#nfc-configuration-of-ptm216b) and change\nthe key.\n\n\nIt's also possible to enable BLE's\n[resolvable private addresses](https://www.bluetooth.com/blog/enhancing-device-privacy-and-energy-efficiency-with-bluetooth-randomized-rpa-updates/),\nin this way every message will be sent from a random, different BLE address.\nThis FW is still able identify the device sending the message using the IRK\n(which is actually the same key used for encryption), but anyone else will\nonly see a random address.\nUnfortunately, the fact that the counter is incremental and always sent in\nplaintext (because it is used as part of the nonce for\ndecryption/authentication) makes it quite easy to correlate different messages\nand indicate them as coming from the same PTM216B device, even if the BLE\naddress changes.\n\n#### Bruteforce protection\n\nWhen a message with a wrong authentication tag is received, that specific\ndevice is blocked (i.e. any packets for it will be ignored even if the have\nthe correct tag) for some time.\nThe length of the ban depends on the distance between the last correct\ncounter observed for the device and the counter of the received message.\nThe rationale is: if the counter is _a lot_ in the future, this may be\na long term bruteforce attack, so we need to apply a long ban to make it\nunfeasible (i.e. 6 hours).\nOn the other hand: if the counter is very close to the current one and\nthe device has been used recently, there is very little time to bruteforce\nit, so a very small delay (i.e. 2 seconds) is enough to make the attack\nunfeasible.\nThis distinction between near and far counters is needed because\notherwise, the anti-bruteforce mechanism could be used against the user\nto carry a DoS attack.\nAn attacker could simply spam the ether with random packets, triggering the\nban and preventing the real PTM216B from delivering its messages.\nA short ban on near counters should mitigate this issue (even if it doesn't\nfix it completely).\nOf course there are always ways to interfere with BLE, so you\ncan't really make this device DoS-proof.\n\n#### Counter\n\nThis FW will discard any message with a counter less or equal to the last\nvalid counter observed.\nThe current counter is also periodically written to flash so that it won't\nrestart from the default value when power is cut.\nThere is a trade-off to be made regarding the frequency of writes:\nmore frequent means that replay attacks are very unlikely even in case of power\ncuts, but they can wear the flash and break it.\nThis FW will save the counters every 20 minutes (if and only if they changed) or\nbefore entering OTA mode.\nThis should ensure several hundreds years of life for the flash, while limiting\nthe scope of replay attacks.\nThere is a mechanism to allow the counter to wrap when it reaches 4294967295,\neven though it is very unlikely that the PTM216B's mechanical parts will still work\nafter 2 billion button press.\n\n#### OTA\n\nPlease refer to [OTA updates security](#ota-updates-security).\n\n#### NFC\n\nPlease refer to [NFC security](#nfc-security).\n\n#### ESP32\n\nESP32 supports [Secure Boot](https://docs.espressif.com/projects/esp-idf/en/v5.5.1/esp32/security/secure-boot-v2.html)\nand [flash encryption](https://docs.espressif.com/projects/esp-idf/en/v5.5.1/esp32/security/flash-encryption.html).\nThis features can be used to prevent a malicious actor from reading or replacing the FW.\n\nUnfortunately, there are some known side-channel attacks that allow to get around these protections.\n\nFortunately, these attacks are quite complex, require physical access to the MCU and\nplenty of time and skills. So for the use case of a simple light switch they shouldn't worry you.\n\n\n#### Reporting security issues\n\nIf you find a security issue with this FW or any of the components\nused by this project, please\n[let me know in private](https://smeso.it/contact).\n\n\nHow to add custom commands\n==========================\n\nIf you want to add some custom command, you just need to create a function in\n`main/events.hpp` inside the `actions` namespace. The function should take no\narguments and return no value. It can block, but blocking for seconds or more\nis not advised, because commands are performed sequentially and not in parallel.\n\nTo use your function, you only need to use its name in the \"action\" field of\nyour `devices.json` file. Just like `light_toggle` and the others.\n\nIf you add more capabilities to your FW, you may want to revise the default\nconfiguration in `sdkconfig.default`.\nThe current one has some power saving options that may not work for you (e.g.\nusing just one core and enabling PM).\n\n\nPower usage\n===========\n\nThe MINIR4 while idle (i.e. waiting for commands with the load off)\nuses around 0.9 W. Over a year it should use less than 8 KWh. YMMV.\n\nThe PTM216B, of course, doesn't use any power.\n\n\nRunning tests\n=============\n\nAt the moment there are no automatic tests!\nOne day I'll get around and add them.\nFor now you need to test everything manually.\n\n\nReporting issues or leaving feedback\n====================================\n\nPlease report issues or feature requests via\n[GitHub](https://github.com/smeso/esp32-ptm216b/issues/new).\n\nIf you want to report a security vulnerability or leave some other\nkind of feedback, please do so [in private](https://smeso.it/contact).\n\n\nContributing\n============\n\n**Thank you** for wanting to contribute to this project!\n\nIn order to not waste your time, you are strongly encouraged to always\n**open an issue before starting working on anything**, there might be\nalready work going on for the same feature or some aspect that\nneeds to be discussed.\n\nAll contribution **must** be made available under\n[Apache 2.0 license](https://opensource.org/license/apache-2-0).\n\n#### Developer Certificate of Origin\n\nI want to make sure that all incoming contributions are correctly attributed and\nlicensed. A Developer Certificate of Origin (DCO) is a lightweight mechanism to\ndo that. The DCO is a declaration attached to every commit.\nIn the commit message of the contribution, the developer simply adds a\n`Signed-off-by` statement and thereby agrees to the DCO, which you can find\nbelow or at [DeveloperCertificate.org](http://developercertificate.org/).\n\n```text\nDeveloper's Certificate of Origin 1.1\n\nBy making a contribution to this project, I certify that:\n\n(a) The contribution was created in whole or in part by me and I\n    have the right to submit it under the open source license\n    indicated in the file; or\n\n(b) The contribution is based upon previous work that, to the\n    best of my knowledge, is covered under an appropriate open\n    source license and I have the right under that license to\n    submit that work with modifications, whether created in whole\n    or in part by me, under the same open source license (unless\n    I am permitted to submit under a different license), as\n    Indicated in the file; or\n\n(c) The contribution was provided directly to me by some other\n    person who certified (a), (b) or (c) and I have not modified\n    it.\n\n(d) I understand and agree that this project and the contribution\n    are public and that a record of the contribution (including\n    all personal information I submit with it, including my\n    sign-off) is maintained indefinitely and may be redistributed\n    consistent with this project or the open source license(s)\n    involved.\n```\n\nEvery contribution should be signed with a DCO. Usage of known identity\n(such as a real or **preferred** name). No anonymous contributions will be\naccepted. A DCO signed commit will contain a line like:\n\n\n```text\nSigned-off-by: Jane Smith \u003cjane.smith@email.com\u003e\n```\n\nYou may type this line on your own when writing your commit messages. However, if your\nuser.name and user.email are set in your git configs, you can use `git commit` with `-s`\nor `--signoff` to add the `Signed-off-by` line to the end of the commit message.\n\n\n#### AI policy\n\nPlease refrain from using any generative AI tool when contributing to this project.\n\n\nTODO\n====\n\nThis is a list of things that I would like to do in random order:\n\n* CI with linters and tests for both the C++ and the Python code\n* Move the ptm216b code to a dedicated and re-usable esp32 component\n* Automated tests to run using 2 ESP32 devkits\n* Add more config options to `nfc.py`. To do so I could:\n    * Ask for more info about the NFC API from Enocean (they helped me once already)\n    * Use the official Windows program and sniff the USB packets to see what it does\n    * Reverse the Windows program to see what it does\n* Add a default per-device start value for the CTR in devices.json\n* Packet replay functionality (to extend the PTM216B range)\n* Add AUTHLIM settings to `nfc.py`\n* [on hold] OTA updates compression: I tried it and the upload time was halved, but I figured\n  that I don't want an external dependency just for this.\n* Properly distribute the various Python tools in `tools/` via PyPI.\n* OTA updates with AES-GCM encrypted FW\n* OTA device selection when multiple devices are in OTA mode at the same time\n* Easier way to update the config without updating the whole FW\n* \"Fleet management system\" over WiFi to distribute FW upgrades and configs.\n* MQTT bridge over WiFi\n\n\nCredits\n=======\n:heart::heart::heart:\n\nThe NFC API of the PTM216B is not publicly documented, I reached out to Enocean for information\nand they have been super helpful! Even though they couldn't share the full documentation with me,\nthey certainly saved me many hours of reversing and debugging, so **thanks a lot to Enocean**!\n\n\nList of vendors and products using PTM216B\n==========================================\n\nThis is a (work in progress) list of finished units\nthat use PTM216B inside:\n\n* [Enocean - Rocker switch](https://www.enocean.com/en/product/easyfit-single-double-rocker-wall-switch-for-ble-ewssb-ewsdb/)\n* [Enocean - Single or double pad](https://www.enocean.com/en/product/easyfit-single-double-rocker-pad-for-ble-esrpb-edrpb/)\n* [VIMAR](https://faidate.vimar.com/it/it/catalog/product/index/code/0K03925.04)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmeso%2Fesp32-ptm216b","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmeso%2Fesp32-ptm216b","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmeso%2Fesp32-ptm216b/lists"}