github.com/martinohmann/rfoutlet@v1.2.1-0.20220707195255-8a66aa411105/README.md (about) 1 rfoutlet 2 ======== 3 4 [![Build Status](https://github.com/martinohmann/rfoutlet/workflows/build/badge.svg)](https://github.com/martinohmann/rfoutlet/actions?query=workflow%3Abuild) 5 [![codecov](https://codecov.io/gh/martinohmann/rfoutlet/branch/master/graph/badge.svg)](https://codecov.io/gh/martinohmann/rfoutlet) 6 [![Go Report Card](https://goreportcard.com/badge/github.com/martinohmann/rfoutlet)](https://goreportcard.com/report/github.com/martinohmann/rfoutlet) 7 [![PkgGoDev](https://pkg.go.dev/badge/github.com/martinohmann/rfoutlet)](https://pkg.go.dev/github.com/martinohmann/rfoutlet) 8 9 Outlet control via web interface for Raspberry PI 2/3/4. The transmitter and 10 receiver logic has been ported from the great 11 [rc-switch](https://github.com/sui77/rc-switch) C++ project to golang. 12 13 ![Raspberry PI Setup](assets/setup.jpg) 14 15 Contents 16 -------- 17 18 - [Screenshots](#screenshots) 19 - [Stability note](#stability-note) 20 - [Breaking changes](#breaking-changes) 21 - [Prerequisites](#prerequisites) 22 - [Installation](#installation) 23 - [Commands](#commands) 24 - [Raspberry PI Setup](#raspberry-pi-setup) 25 - [Outlets](#outlets) 26 - [Running rfoutlet as systemd service](#running-rfoutlet-as-systemd-service) 27 - [Development / Testing](#development--testing) 28 - [Todo](#todo) 29 - [License](#license) 30 - [Resources](#resources) 31 32 Screenshots 33 ----------- 34 35 Some screenshots of the web app that controls the outlets. 36 37 Main Outlet View | Schedule View | Settings View 38 :------------------------------------------: | :-------------------------------------------: | :---------------------------------------------------: 39 ![Screenshot](assets/screenshot_outlets.jpg) | ![Screenshot](assets/screenshot_schedule.jpg) | ![Raspberry PI Setup](assets/screenshot_settings.jpg) 40 41 Stability note 42 -------------- 43 44 The *master* branch may be broken at any time. Please check out the latest tag 45 or use the latest [release](https://github.com/martinohmann/rfoutlet/releases). 46 47 Breaking changes 48 ---------------- 49 50 ### v0.5.0 to v1.0.0 51 52 Due to a complete rewrite of the internal logic, many API inconsistencies have 53 been fixed. This introduces non-backwards-compatible changes. 54 55 - The config file format changed completely, please have a look at [the 56 example](configs/config.yml) and adjust your config accordingly. 57 - The state file format changed, so that old file cannot be loaded with the new 58 version. It is advised to start with a fresh state file. If you have a lot of 59 state, make a backup before upgrading and manually convert the state file 60 json to the new format. In the following example `foo` and `bar` are the IDs 61 of the outlets in the state file. 62 63 Old format: 64 ```json 65 {"switch_states":{"bar":1,"foo":1},"schedules":{"foo":[{"enabled": true,"weekdays":[1],"from":{"hour":0,"minute":59},"to":{"hour":2,"minute":1}}]}} 66 ``` 67 New format: 68 ```json 69 {"bar":{"state":1},"foo":{"state":1,"schedule":[{"enabled": true,"weekdays":[1],"from":{"hour":0,"minute":59},"to":{"hour":2,"minute":1}}]}} 70 ``` 71 - `rfoutlet serve`: 72 - `--gpio-pin` flag was renamed to `--transmit-pin` as it now 73 also supports `--receive-pin` for state drift detection. 74 - `rfoutlet sniff`: 75 - `--gpio-pin` flag was renamed to `--pin`. 76 - `rfoutlet transmit`: 77 - `--gpio-pin` flag was renamed to `--pin`. 78 - The command now accepts a list of codes that are transmitted sequentially. 79 - The websocket message format changed slightly, so the web frontend needs to 80 be rebuilt (see [installation](#installation) section). 81 - In the package `pkg/gpio` the usage of 82 [gpio](https://github.com/brian-armstrong/gpio) was replaced with 83 [gpiod](https://github.com/warthog618/gpiod) to get rid of the dependency on 84 the deprecated GPIO interface which may be removed from the linux kernel this 85 year. This was also a good opportunity to improve the public API of 86 `pkg/gpio`. 87 - Instead of `/dev/gpiomem`, rfoutlet now depends on `/dev/gpiochip0`. 88 - Since v1.0.0 does not depend on the sysfs anymore, the GPIO pins have to be 89 unexported there to avoid `device busy` errors. This can be done like this: 90 ```bash 91 # Replace 17 and 27 with the GPIO pin you are using for transmitting and 92 # receving rf codes if you are not using the defaults. 93 echo "17" > /sys/class/gpio/unexport 94 echo "27" > /sys/class/gpio/unexport 95 ``` 96 97 Prerequisites 98 ------------- 99 100 See the [Raspberry PI Setup](#raspberry-pi-setup) section for setup of hardware 101 and required software. 102 103 ### Hardware 104 105 - Raspberry PI 2, 3 or 4 106 - Remote controlled outlets (see [Outlets](#outlets) section for suggestions) 107 - Receiver/Transmitter (e.g. 108 [this](https://www.amazon.com/SMAKN%C2%AE-433Mhz-Transmitter-Receiver-Arduino/dp/B00M2CUALS/ref=sr_1_3?s=electronics&ie=UTF8&qid=1541529103&sr=1-3&keywords=433mhz+receiver+transmitter)) 109 - SD Card 110 - Power supply 111 - Wiring 112 - Breadboard (optional) 113 114 ### Software 115 116 - I use Arch Linux on the Raspberry PI, but Raspbian should also work 117 - nodejs 15.0+ 118 - golang 1.13+ 119 - `make` 120 121 Older software versions may also work, but I did not test that. 122 123 Installation 124 ------------ 125 126 ### Using `go get` 127 128 Obtain the source, build and install it as follows: 129 130 ```sh 131 go get -u github.com/martinohmann/rfoutlet 132 cd $GOPATH/src/github.com/martinohmann/rfoutlet 133 make all 134 make install 135 ``` 136 137 You will find a new binaries below `$GOPATH/bin`: `rfoutlet`. 138 139 If you only want to use the gpio transmitter and receiver code below 140 [pkg/gpio/](pkg/gpio/) for your own project, just `go get` the project and 141 check out the code in [cmd/sniff.go](cmd/sniff.go) and 142 [cmd/transmit.go](cmd/transmit.go) for example usage. 143 144 ```sh 145 go get -u github.com/martinohmann/rfoutlet/pkg/gpio 146 ``` 147 148 ## Using docker 149 150 Pre-built images of tagged releases and `master` are available on [Docker 151 Hub](https://hub.docker.com/r/mohmann/rfoutlet). `mohmann/rfoutlet:latest` will 152 always point to the latest tagged release. 153 154 If you prefer building locally, run: 155 156 ```sh 157 docker build -t mohmann/rfoutlet . 158 ``` 159 160 161 ### Running via docker-compose 162 163 Simply run: 164 165 ```sh 166 docker-compose up -d 167 ``` 168 169 This pulls `mohmann/rfoutlet:latest` and starts the `rfoutlet` container listening on port 170 `3333`. 171 172 ### Running via docker 173 174 Start the container and browse to `<raspberry-ip-address>:3333`: 175 176 ```sh 177 docker run \ 178 --rm \ 179 --privileged \ 180 -p 3333:3333 \ 181 -v /etc/localtime:/etc/localtime:ro \ 182 -v $(pwd)/configs/config.yml:/etc/rfoutlet/config.yml:ro \ 183 mohmann/rfoutlet:latest 184 ``` 185 186 The container has to run in privileged mode in order to be able to access 187 `/dev/gpiochip0`. 188 189 Commands 190 -------- 191 192 Note: all commands requires `sudo` in order to access `/dev/gpiochip0`. 193 194 ### `serve` command 195 196 This command starts a server which listens on `0.0.0.0:3333` by default. 197 198 By default it looks for its configuration file at `/etc/rfoutlet/config.yml`. 199 Check [configs/config.yml](configs/config.yml) for an example config file with 200 all available config values. Use the `sniff` command for reading the on/off 201 codes, protocol and pulse lengths for your outlets to put into the 202 configuration file. 203 204 Start the server: 205 206 ```sh 207 sudo rfoutlet serve --listen-address 0.0.0.0:3333 \ 208 --config /etc/rfoutlet/config.yml --transmit-pin 17 209 ``` 210 211 By default rfoutlet uses gpio pin 17 (physical 11 / wiringPi 0) for 212 transmission of the rf codes. A different pin can be use by providing the 213 `--transmit-pin` flag. Check out the [Raspberry Pi pinouts](https://pinout.xyz/) for 214 reference. 215 216 If you want the outlet switch states to be persisted, pass the `--state-file` flag, e.g: 217 218 ```sh 219 sudo rfoutlet serve --state-file /var/lib/rfoutlet/state.json 220 ``` 221 222 ### `sniff` command 223 224 This command listens on a gpio pin and tries to sniff codes sent out by 433 Mhz 225 remote controls. It will print the received code, protocol, pulse length and 226 bit length to stdout when you press the on/off buttons on your remote. 227 228 ```sh 229 sudo rfoutlet sniff --pin 27 230 ``` 231 232 ### `transmit` command 233 234 This command sends out remote control codes on the provided gpio pin. It can be used 235 for testing or you can wrap it for use in another application. 236 237 Example for sending out the code `123456`: 238 239 ```sh 240 sudo rfoutlet transmit --pin 17 --protocol 1 --pulse-length 189 123456 241 ``` 242 243 Raspberry PI Setup 244 ------------------ 245 246 ### Install required software 247 248 On Arch Linux the following commands should be sufficient to install the 249 required software: 250 251 ```sh 252 sudo pacman -Sy go nodejs npm make 253 ``` 254 255 On Raspbian the following should do (untested): 256 257 ```sh 258 wget https://storage.googleapis.com/golang/go1.15.5.linux-armv6l.tar.gz 259 sudo tar -C /usr/local -xvf go1.15.5.linux-armv6l.tar.gz 260 rm go1.15.5.linux-armv6l.tar.gz 261 curl -sL https://deb.nodesource.com/setup_15.x | sudo -E bash - 262 sudo apt-get install -y build-essential nodejs 263 ``` 264 265 Set up `$GOPATH` afterwards: 266 267 ```sh 268 cat >> ~/.bashrc << 'EOF' 269 export GOPATH=$HOME/go 270 export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin 271 EOF 272 source ~/.bashrc 273 ``` 274 275 ### Wiring transmitter and receiver 276 277 The wiring of transmitter and receiver is straight forward and can be best 278 described using images: 279 280 Transmitter | Receiver 281 :-------------------------------------:|:-------------------------------: 282 ![Transmitter](assets/transmitter.jpg) | ![Receiver](assets/receiver.jpg) 283 284 To increase the range of the transmitter I initially used a 25cm wire as antenna. I just 285 twisted it with a pair of pliers to hold it in place, soldering is optional. 286 This covers my whole appartment (105sqm). YMMV. Switched to [transmitters and 287 receivers with antennas already soldered 288 on](https://www.amazon.de/gp/product/B071J2Z3YK/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&language=en_GB&psc=1) 289 later. 290 291 Outlets 292 ------- 293 294 I achieved good results with the following remote controlled outlets: 295 296 - [Etekcity Remote Control Outlet Wireless Light Switch](https://www.amazon.com/Etekcity-Household-Appliances-Unlimited-Connections/dp/B00DQELHBS/ref=sr_1_4?ie=UTF8&qid=1541529214&sr=8-4&keywords=etekcity+remote+control+outlet+wireless) 297 - [Brennenstuhl RCS 1000 N Comfort](https://www.amazon.de/gp/product/B001AX8QUM/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1) 298 299 Please let me know about others that work well too, so I can extend the list here. 300 301 Running rfoutlet as systemd service 302 ----------------------------------- 303 304 See [init/systemd/rfoutlet.service](init/systemd/rfoutlet.service) for an 305 example systemd service file. 306 307 Development / Testing 308 --------------------- 309 310 rfoutlet is meant to run on a Raspberry PI 2/3/4 to work properly. However, for 311 development purposes you can also run it on your local machine. If your 312 development box does not have `/dev/gpiochip0`, you can load the `gpio-mockup` 313 kernel module to create a mockup: 314 315 ```bash 316 sudo make load-gpio-mockup 317 ``` 318 319 To unload the gpio-mockup kernel module again, run: 320 321 ```bash 322 sudo make unload-gpio-mockup 323 ``` 324 325 A more convenient way to automatically load the `gpio-mockup` kernel module and 326 unload it again is to simply pass the `--gpio-mockup` flag to rfoutlet: 327 328 ```bash 329 sudo rfoutlet --gpio-mockup [...] 330 ``` 331 332 Run `make` without arguments to see available commands for building and testing. 333 334 Todo 335 ---- 336 337 - [x] implement code transmitter (see [cmd/transmit.go](cmd/transmit.go)) 338 - [x] implement code receiver (see [cmd/sniff.go](cmd/sniff.go)) 339 - [x] make transmitter/receiver code available as library below [pkg/gpio/](pkg/gpio/) 340 - [x] persist outlet state across server restarts 341 - [x] use receiver to detect outlet state changes (see `--detect-state-drift` 342 flag of the `serve` command) 343 - [x] time switch: switch outlets on/off using user defined rules (e.g. fixed 344 time or relative) 345 - [x] use web sockets for communication to be able to push outlet state changes 346 to multiple clients 347 348 License 349 ------- 350 351 The source code of this is released under the MIT License. See the bundled LICENSE 352 file for details. 353 354 [![Creative Commons License](https://i.creativecommons.org/l/by-nc/4.0/80x15.png)](http://creativecommons.org/licenses/by-nc/4.0/) 355 356 The images belonging to this project are licensed under a [Creative Commons 357 Attribution-NonCommercial 4.0 International 358 License](http://creativecommons.org/licenses/by-nc/4.0/). 359 360 Resources 361 --------- 362 363 - [Raspberry Pi pinouts](https://pinout.xyz/) 364 - [Wireless Power Outlets](https://timleland.com/wireless-power-outlets/) 365 - [ninjablocks 433Utils](https://github.com/ninjablocks/433Utils) 366 - [rc-switch](https://github.com/sui77/rc-switch) 367 - [WiringPi](https://projects.drogon.net/raspberry-pi/wiringpi/download-and-install/)