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/)