{"id":15145358,"url":"https://github.com/latchdevel/raspicode","last_synced_at":"2026-03-06T08:31:34.694Z","repository":{"id":59997006,"uuid":"540526267","full_name":"latchdevel/raspicode","owner":"latchdevel","description":"High precision transmitter RF 315/433Mhz codes for Raspberry Pi","archived":false,"fork":false,"pushed_at":"2024-05-10T16:22:13.000Z","size":573,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-05T10:32:08.005Z","etag":null,"topics":["315mhz","433mhz","api","ask","flask","gpio","ook","picode","picoder","pilight","raspberry","restful","rf","transmitter","wiringpi","wiringpiook"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/latchdevel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-23T16:25:02.000Z","updated_at":"2024-06-23T13:09:38.000Z","dependencies_parsed_at":"2025-02-09T01:41:18.023Z","dependency_job_id":null,"html_url":"https://github.com/latchdevel/raspicode","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/latchdevel/raspicode","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/latchdevel%2Fraspicode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/latchdevel%2Fraspicode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/latchdevel%2Fraspicode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/latchdevel%2Fraspicode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/latchdevel","download_url":"https://codeload.github.com/latchdevel/raspicode/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/latchdevel%2Fraspicode/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30167962,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T07:56:45.623Z","status":"ssl_error","status_checked_at":"2026-03-06T07:55:55.621Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["315mhz","433mhz","api","ask","flask","gpio","ook","picode","picoder","pilight","raspberry","restful","rf","transmitter","wiringpi","wiringpiook"],"created_at":"2024-09-26T11:23:52.152Z","updated_at":"2026-03-06T08:31:34.662Z","avatar_url":"https://github.com/latchdevel.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Raspicode\nHigh precision Python transmitter of RF 315/433Mhz codes for Raspberry Pi using GPIO via Wiring Pi C library.\n\nImplementation example as simple RESTful API Flask Web Server based to transmit \"pilight\" string format RF 315/433 Mhz codes named \"picode\".\n\nThe \"pilight\" project defines a special string format to easily transcribe an OOK pulse train, in order to be able to exchange it with other systems, such as a remote RF receiver/transmitter. \n\nAlmost all wireless protocols of RC switches or weather stations use ASK/OOK pulse modulation to encode commands or other messages. See: https://github.com/latchdevel/picoder\n\nPicode format: `c: \u003cpulses_index\u003e ; p: \u003cpulse_0_lenght\u003e, \u003cpulse_1_lenght\u003e, ... \u003cpulse_n_lenght\u003e [;r:\u003crepeats\u003e] @`\n\nPicode example: `c:011010100101011010100110101001100110010101100110101010101010101012;p:1400,600,6800@`\n\nTransmit example: \n```bash\n$ curl \"http://localhost:8087/picode/c:011010100101011010100110101001100110010101100110101010101010101012;p:1400,600,6800@\"\nRF TX sent picode in 286 ms OK\n``` \n\n## The timing problem\nThe RF protocols use AM ASK modulation to encode OOK pulse trains. The length of ON/OFF pulses is of microseconds range, from 100 uSecs for the shortest ones, up to 100,000 uSecs for the longest ones, which are usually used as final OFF pulse to separation between repeats (footer pulse).\n\nManaging such small time periods accurately is easy for microcontrollers like Atmel/Pic or others commonly used with Arduino framework.\nBut it is a big challenge for a Linux system, and much more to do it in a high-level interpreted language like Python.\n\nThere are several approaches:\n- **Very poor**: Using \"time\" module like as `time.sleep(usecs/1000000.0)` argument may be a floating point number to indicate a more precise sleep time.\n- **Poor**: From Python 3.7 \"time\" module have `time.time_ns()` function that returns time as an integer number of nanoseconds since the epoch. \n- **Poor**: Using \"ctypes\" to call dynamic C library `usleep()` function. See: https://github.com/ElectricRCAircraftGuy/eRCaGuy_PyTime\n- **Excellent**: Python C Extension Module to implement a high precision time handling in low-level C language.\n\n## Wiring Pi: the solution for everything\nWiringPi is a GPIO access library written in C for SoC devices used in all Raspberry Pi.\nIt's designed to be familiar to people who have used the Arduino \"wiring\" system and is intended for use by experienced C/C++ programmers.\n\nThe WiringPi is very extensive, includes support for many devices, several protocols and operation modes, but since the functionality required is very limited and specific, only the two main files `wiringPi.h` and `wiringPi.c` have been required with minor modifications for ease of use:\n\n- Remove softPwm and softTone support\n- Remove all PWM init modes\n- Remove threads functions\n- Remove scheduling priority piHiPri \n- Expose delayMicrosecondsHard function\n\nWiring Pi is the ideal solution to handle digital GPIOs and solve the timing problem through its **delayMicrosecondsHard()** function.\nThere are other ways to handle GPIOs, but they are not as simple or as widespread. See: https://elinux.org/RPi_GPIO_Code_Samples\n\n### delayMicrosecondsHard(unsigned int howLong)\nHard loop for watching a built-in counter on the ARM SoC. This uses 100% of assigned CPU something not an issue for recent multi-core SoCs.\n```c\nvoid delayMicrosecondsHard (unsigned int howLong)\n{\n  struct timeval tNow, tLong, tEnd ;\n\n  gettimeofday (\u0026tNow, NULL) ;\n  tLong.tv_sec  = howLong / 1000000 ;\n  tLong.tv_usec = howLong % 1000000 ;\n  timeradd (\u0026tNow, \u0026tLong, \u0026tEnd) ;\n\n  while (timercmp (\u0026tNow, \u0026tEnd, \u003c))\n    gettimeofday (\u0026tNow, NULL) ;\n}\n```\n\n## WiringPiOOK\nPython C Extension Module to send OOK pulse train to digital GPIO using wiringPi library.\n\nUse only these four native C functions:\n\n- **wiringPiSetupGpio()** to initialize wiringPi GPIO manage via native Broadcom GPIO numbers.\n- **pinMode(gpio,mode)** to configure the specified GPIO number to behave either as OUTPUT. \n- **digitalWrite(gpio,state)** to set GPIO state, HIGH for odd pulse index or LOW for even pulse index.\n- **delayMicrosecondsHard(usecs)** to high precision microseconds program execution pause.\n\nRequires install standard Python modules: **setuptools** and **flask** (for API server):\n - Install via OS package manager: `apt install python3-setuptools python3-flask`\n - Or install via **pip** Python package manager:\n   - Install **pip**: `apt install python3-pip` and `pip install setuptools flask`\n\nRequires build C extension Python module: **wiringpiook**\n\nTo build the module:\n```sh\n$ cd wiringpiook\n$ python3 setup.py develop --user\n```\n\nThe \"**wiringpiook**\" module only has the function \"**tx()**\", to transmit pulse train using gpio digital levels.\nReturn total transmission time in milliseconds or a negative error code.\n\nUsage: `tx(bcm_gpio, pulse_list, repeats = 4)`\n\nExample:\n```python\n\u003e\u003e\u003e import wiringpiook as rf\n\u003e\u003e\u003e rf.tx(21,[500,500,2000,2000])\n\u003e\u003e\u003e 20\n```\n\nThe pulse list can be Python generated by [pyPiCode](https://github.com/latchdevel/pyPiCode) module, from any **picode** string or encoding any [pilight supported RF protocols.](https://github.com/latchdevel/picoder?tab=readme-ov-file#show-protocol-list)\n\n## Process affinity to isolated CPU\nFor better timing accuracy when code transmit, the Python script should be executed in a CPU isolated from the OS scheduler.\n\nCPU isolation is a powerful set of features that can be found behind the settings for workloads which rely on specific and often extreme latency or performance requirements. \n\n\"isolcpus\" is one of the Linux kernel boot params that isolated certain cpus from kernel scheduling, which is especially useful if you want to dedicate some cpus for special tasks with least unwanted interruption (but cannot get to zero) in a multi-core system.\n\nRemove the specified CPUs, as defined by the cpu_number values, from the general kernel SMP balancing and scheduler algorithms.\n\nRaspberry Pi models 2, 3, 4 and Zero 2, have 4 cores, cpus: `{0,1,2,3}`, so is possible to dedicate one CPU to improve the transmission without much impact over system.\n\nAdd `isolcpus=3` to file `/boot/cmdline.txt` and reboot system.\n\nExample of `/boot/cmdline.txt` file::\n```\nconsole=serial0,115200 console=tty1 root=PARTUUID=47cac5b4-02 rootfstype=ext4 fsck.repair=yes rootwait isolcpus=3\n```\n\nTo verify:\n```bash\n$ cat /sys/devices/system/cpu/isolated\n3\n```\n\nTo manual set cpu affinity when run a program use:\n```\n$ taskset -c 3 ./raspicode.py\n```\n\nAnyway, if there are CPUs isolated from the OS, Python script will try to set affinity to one of the isolated CPUs:\n```\n[2022-09-19 00:24:38,782] 1388 WARNING - Process id: 1388 not OS scheduler isolated cpu process affinity\n[2022-09-19 00:24:38,784] 1388 WARNING - Trying to set process affinity cpu: {3}\n[2022-09-19 00:24:38,786] 1388 INFO - OK Process id: 1388 affinity cpu: {3} isolated from OS scheduler cpu: {0, 1, 2}\n[2022-09-19 00:24:38,787] 1388 INFO - Web server binding to 0.0.0.0 port 8087 local url http://192.168.1.49:8087/\n```\n\n## GPIO\nWiringPi defines 17 GPIOs (21 from Rev 2 board), but some of them and the functions we can use may potentially cause problems with other parts of the Raspberry Pi Linux system.\n\nGPIOs that have specific uses on the Raspberry Pi should be avoided:\n- GPIO02 and GPIO03 are used by internal I2C bus and are always in a high state (pull-up).\n- GPIO14 and GPIO15 are used by internal UART for bluetooth or serial console.\n- GPIO07, GPIO08, GPIO09, GPIO10, and GPIO11 are used by internal SPI bus.\n- GPIO04 is used by internal 1-Wire bus.\n\n![Raspberry Pi GPIO](images/RaspberryPi_GPIO.png)\n\nThe Raspberry Pi is a 3.3 volt device! Attempting to directly connect to any 5V logic system  will very likely result in tears…\n\nSee: http://wiringpi.com/pins/special-pin-functions/\n\n## Accuracy test\n\nAccuracy test from 5 microSeconds to 100000 microSeconds (0.1 Sec), 195 pulses (logarithmic distribution).\n\nTest environment:\n- Raspberry Pi 3B+ running Debian (bullseye) kernel 5.15.61-v8+ 64-bit.\n- Process affinity to OS scheduler isolated cpu: {3}.\n- Output GPIO: 21.\n- Measured by Saleae Logic16 (clone) logic analyzer using Logic 2 (v2.4.0) software. See: https://www.saleae.com/\n- Sample rate: 100MS/s (nanoSeconds resolution).\n\n![Seleae Logic16 - Session 1](accuracy_test/Session1.png)\n\n### Results:\n- Only two pulses (1%) above the acceptable error range.\n- Median rate error below 0.004% (0.6% average).\n\n![Raspicode Accuracy Test](accuracy_test/accuracy_test.png) \n\n### Conclusions:\n- Excellent general performance.\n- Ready to RF transmit codes.\n\n## STX882: The best cheap RF transmitter module\nLow Cost \u0026 High power: 315/433MHz ASK Transmitter Module STX882 from NiceRF: https://www.nicerf.com/products/detail/433mhz-ask-transmitter-module-stx882.html\n\nThe STX882 datasheet says \"RF Power\" up to 20dBm at 5v, but in my measurements I only got a little over 17dBm (50mW), which is very good, as well as having low harmonic distortion.\n\nIt is certainly the best cheap RF transmitter module, you can see an interesting comparison in this blog: http://x311.blogspot.com/2017/10/comparison-of-cheap-rf-modules-with-ask.html\n\n  ![Raspicode landing page](images/STX882.jpg)\n\nWire connections:\n  - RF TX module VCC pin to Raspberry Pi pin 2 (5vcc).\n  - RF TX module GND pin to Raspberry Pi pin 6 (GND).\n  - RF TX module DATA pin to Raspberry Pi pin 12 (GPIO18).\n  - RF TX module ANTENNA pin to an antenna tuned to specific frequency used.\n\nRemember that in any radio frequency system, the most important element is the antenna.\n\n## API endpoints:\n- `/picode/:picode` method \"GET\" to transmit the \"picode\". \n\n  Multiline picodes are allowed. The characters `+`, `\\n` and others are valid for splitting. In multiline picodes the default repeat is 1 instead of 4.\n\n  Returns plain text picode transmission result, showing the total TX time in milliseconds or an error description on failure.\n\n  Example:\n    ```bash\n      $ curl \"http://localhost:8087/picode/c:011010100101011010100110101001100110010101100110101010101010101012;p:1400,600,6800;r:4@+c:011010100101011010100110101001100110010101100110101010101010101012;p:1400,600,6800;r:4@\"\n      RF TX sent picode in 571 ms OK\n    ```\n\n- `/picode` method \"GET\" or \"POST\" with \"picode\" form parameter to transmit a picode.\n\n  Multiline picodes are allowed. The characters `+`, `\\n` and others are valid for splitting. In multiline picodes the default repeat is 1 instead of 4.\n\n  Returns plain text picode transmission result, showing the total TX time in milliseconds or an error description on failure.\n  \n  Examples:\n    ```bash\n      $ curl -X POST -d \"picode=c:011010100101011010100110101001100110010101100110101010101010101012;p:1400,600,6800@\" http://localhost:8087/picode\n      RF TX sent picode in 286 ms OK\n\n      $ curl -X GET \"http://localhost:8087/picode?picode=c:011010100101011010100110101001100110010101100110101010101010101012;p:1400,600,6800@\"\n      RF TX sent picode in 286 ms OK\n    ```\n\n- `/status` method \"GET returns json status:\n    ```json\n      {\n        \"isolated_cpu_affinity\": \"{3}\", \n        \"last_tx\": \"2022-09-22 20:22:21\", \n        \"logs_directory\": \"/home/pi/raspicode/logs/\", \n        \"proccess_pid\": 1052, \n        \"script_path\": \"/home/pi/raspicode/raspicode.py\", \n        \"start_time\": \"2022-09-22 20:19:39\", \n        \"tx_count\": 2, \n        \"uptime\": \"8 minutes, 21 seconds\"\n      }\n    ```\n- `/config` method \"GET\" return json config:\n    ```json\n      {\n        \"digest\": \"4460c931f5eeae6d631196d8ab4a3c0d\", \n        \"listen_ip\": \"0.0.0.0\", \n        \"listen_port\": \"8087\", \n        \"log_name\": \"web_internal.log\", \n        \"logs_dir\": \"logs\", \n        \"tx_gpio\": 18\n      }\n    ```\n\n### Logs access:\n- `/logs` method \"GET\" to request the HTML directory logs file explorer.\n\n- `/logs/:filename` method \"GET\" to request a text plain file log.\n\n### Landing page:\n- `/` method \"GET\" to request the HTML \"landing page\":\n\n![Raspicode landing page](images/LandingPage.png)\n\n\n# License\nCopyright (c) 2022-2024 Jorge Rivera. All right reserved.\n\nLicense GNU Lesser General Public License v3.0.\n\nThis library is free software; you can redistribute it and/or\nmodify it under the terms of the GNU Lesser General Public\nLicense as published by the Free Software Foundation; either\nversion 3 of the License, or (at your option) any later version.\n\nThis library is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\nLesser General Public License for more details.\n\nYou should have received a copy of the GNU Lesser General Public License \nalong with this library; if not, write to the Free Software Foundation, \nInc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.\n\nSee the [LICENSE](LICENSE.md) file for license rights and limitations (lgpl-3.0).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flatchdevel%2Fraspicode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flatchdevel%2Fraspicode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flatchdevel%2Fraspicode/lists"}