Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
e5cf1d2
Removed timestamp and changed ouput to JSON format
tubalainen Dec 4, 2017
1d006da
Updated information
tubalainen Dec 4, 2017
19e1202
Updates URL to facebook group
tubalainen Dec 4, 2017
ad5f68b
Added MQTT info, mothly automation and node-red parsing
tubalainen Dec 28, 2017
2968dd0
minor adjustments
tubalainen Dec 28, 2017
3a86c41
minor update
tubalainen Dec 28, 2017
28188f3
Added trouble shooting information
tubalainen Dec 28, 2017
18089d2
Adding information on git clone and path´s
tubalainen Dec 28, 2017
dbf64de
Added sleep command
Naesstrom Dec 30, 2017
50fa974
Merge pull request #1 from Naesstrom/master
tubalainen Dec 30, 2017
dd15d9a
Fixed quotations in the JSON output
tubalainen Jan 4, 2018
457629b
Updated information on multiple transmitters
tubalainen Jan 4, 2018
dbc7f07
Update README.md
JohanLeirnes Jan 9, 2018
c7f2d21
Update sparsnas_decode.cpp
JohanLeirnes Jan 9, 2018
b8e5849
Update sparsnas_decode.cpp
JohanLeirnes Jan 9, 2018
ade0344
Update sparsnas_decode.cpp
JohanLeirnes Jan 9, 2018
6d4fc87
Update README.md
JohanLeirnes Jan 10, 2018
f63add8
Merge pull request #2 from bhaap/patch-1
tubalainen Jan 10, 2018
ef9eedf
Updated "Bad" printout to JSON format
tubalainen Jan 10, 2018
7403cae
Update README.md
JohanLeirnes Jan 10, 2018
c8b2049
Update sparsnas_decode.cpp
JohanLeirnes Jan 10, 2018
f6b94ae
Update sparsnas_decode.cpp
JohanLeirnes Jan 10, 2018
961854c
Merge pull request #3 from bhaap/patch-2
tubalainen Jan 10, 2018
253b387
Cleaned the sensor naming
tubalainen Jan 10, 2018
6c74e52
Typo mistake
tubalainen Jan 10, 2018
12f730c
Minor changes
tubalainen Jan 10, 2018
be7d2e6
Update sparsnas_decode.cpp
JohanLeirnes Jan 10, 2018
43bbff1
Update sparsnas_decode.cpp
JohanLeirnes Jan 10, 2018
25a0f6d
Merge pull request #4 from bhaap/patch-2
tubalainen Jan 11, 2018
d21e572
Update with ESP8266 information and decoding
tubalainen Jan 12, 2018
be7dd2e
Update sparsnas_decode.cpp
JohanLeirnes Jan 14, 2018
3309d90
Merge pull request #5 from bhaap/patch-2
tubalainen Jan 14, 2018
439da11
Fixed typo in automation example
tubalainen Jan 15, 2018
b8a04ba
Ported automation old to "new syntax" for automation
tubalainen Jan 24, 2018
edb18f4
Update README.md
JohanLeirnes Feb 1, 2018
2191b33
initial support to run in docker
fredrike Feb 5, 2018
3300f53
verified setting, thanks to @martikainen87
fredrike Feb 6, 2018
43055d1
docker support with automatic configuration
fredrike Feb 8, 2018
603a21d
changed the gain of rtl_sdr
fredrike Feb 9, 2018
0a32045
exit with pipe errors (set -e)
fredrike Feb 9, 2018
03c065c
export all variables to subsequent commands (set -a)
fredrike Feb 9, 2018
f96eb2a
Merge pull request #6 from bhaap/patch-3
tubalainen Feb 10, 2018
76304e2
Added https://github.com/kodarn/Sparsnas
tubalainen Feb 11, 2018
7329d40
better json output, errors to stderr & function fix
fredrike Feb 14, 2018
a7cd5a8
fix of compilation errors
fredrike Feb 14, 2018
7788d25
support for mqtt_publish
fredrike Feb 14, 2018
01534c8
support for multiple senders and docker mqtt support
fredrike Feb 14, 2018
5412970
Merge pull request #1 from fredrike/native_MQTT_support
fredrike Feb 14, 2018
b3b5255
Example dashboard for grafana
fredrike Feb 14, 2018
407b539
package example for Home Assistant
fredrike Feb 14, 2018
d9af93a
fix in Dockerfile
fredrike Feb 14, 2018
803e56e
use busybox version of timeout
fredrike Feb 15, 2018
f2ae44b
added pipefail to sparsnas.sh
fredrike Feb 15, 2018
04faf5a
stupid error in pulses env
fredrike Feb 16, 2018
0f8c90e
Merge pull request #9 from fredrike/homeassistant
tubalainen Feb 25, 2018
fc65cd2
Merge pull request #8 from fredrike/grafanaExample
tubalainen Feb 25, 2018
877828f
Updated documentation
fredrike Feb 25, 2018
b064111
Added functional reconnect for mqtt (#2)
JohanLeirnes Mar 1, 2018
86786a3
Merge branch 'master' into dockerVersion
tubalainen Mar 1, 2018
c96a07a
Merge pull request #7 from fredrike/dockerVersion
tubalainen Mar 1, 2018
508c182
updated automations for home-assistant
fredrike Mar 1, 2018
2fddf7d
added configuration options for custom-ui
fredrike Mar 1, 2018
404c611
changed state_topic to use !secret sparsnas_sensor
fredrike Mar 1, 2018
b6f9beb
Update readme.md
fredrike Mar 1, 2018
556f34d
Minor adjustments
tubalainen Mar 1, 2018
0ffa81a
Minor adjustments
tubalainen Mar 1, 2018
d31d091
Updates
tubalainen Mar 1, 2018
07a374e
Merge pull request #10 from fredrike/homeassistant
tubalainen Mar 1, 2018
c6b8c55
Fixed URL for docker
tubalainen Mar 1, 2018
008819f
fix for power calculation when data4 is 0
fredrike Mar 2, 2018
06e0690
minor fixes in the automation syntax
fredrike Mar 2, 2018
b7f7ca0
Merge pull request #12 from fredrike/data4_is_0
tubalainen Mar 2, 2018
0650812
Merge pull request #13 from fredrike/patch-1
tubalainen Mar 2, 2018
e2b4ff0
Typo
tubalainen Mar 2, 2018
743a17e
minor updates
tubalainen Mar 5, 2018
869d73f
minor fixes in docker version
fredrike Mar 6, 2018
2f1ff7c
Merge pull request #14 from fredrike/dockerUpdates
tubalainen Mar 8, 2018
66f3775
Mosquitto handles reconnect automatically
fredrike Jul 2, 2018
44169af
Merge pull request #15 from fredrike/patch-1
tubalainen Jul 4, 2018
215a4aa
Typo
tubalainen Jul 5, 2018
980c12a
Update Dockerfile
fredrike Mar 22, 2019
717d8d3
divide as float instead
fredrike Mar 22, 2019
740d43f
Merge pull request #18 from fredrike/patch-3
tubalainen Mar 27, 2019
ea034f9
Merge pull request #17 from fredrike/patch-2
tubalainen Mar 27, 2019
99b8bce
style fix for output string
fredrike Apr 2, 2019
a422428
Update on SDR dongle models
tubalainen Apr 20, 2019
ef7630d
hassio updates
tubalainen Apr 20, 2019
a3d4023
Pin Alpine version to 3.7
JariInc Jul 20, 2019
b3ad5f1
Reorder commands for better caching
JariInc Jul 20, 2019
5bfc049
Remove empty line
JariInc Jul 24, 2019
058d10a
Remove deprecated -t parameter
JariInc Jul 24, 2019
0b71734
Revert "Pin Alpine version to 3.7"
JariInc Jul 24, 2019
5cc6861
Merge pull request #19 from JariInc/pin-alpine-version
fredrike Jul 24, 2019
2ec8b74
Clarification on sender id
tubalainen Aug 4, 2019
e7dbb8f
Six not eight ..
tubalainen Aug 4, 2019
e71ab29
Updated
tubalainen Jun 12, 2020
1a9577b
Update again
tubalainen Jun 12, 2020
50f6fb8
Gah
tubalainen Jun 12, 2020
9271be6
Some config generates errors
parhedberg Sep 8, 2021
95bc53d
Enable energy dashboard
parhedberg Sep 9, 2021
b220ff7
Merge pull request #30 from parhedberg/patch-1
tubalainen Sep 9, 2021
99ec0a3
Merge pull request #29 from parhedberg/patch-2
tubalainen Sep 9, 2021
19d57be
Update README.md
tubalainen Dec 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# docker build --build-arg SENSORS="12 10000" \
# --build-arg MQTT_HOST=192.168.x.x --build-arg MQTT_PORT=1883 \
# --build-arg=MQTT_USERNAME=username --build-arg=MQTT_PASSWORD=hemligt

FROM alpine:edge as BUILD_ENV

COPY ./sparsnas_decode.cpp /build/

RUN apk add --no-cache g++ mosquitto-dev && \
g++ -o /build/sparsnas_decode -O2 -Wall /build/sparsnas_decode.cpp -lmosquitto

FROM alpine:edge

ARG SENSORS
ARG MQTT_HOST
ARG MQTT_PORT
ARG MQTT_USERNAME
ARG MQTT_PASSWORD
ENV MQTT_HOST=${MQTT_HOST:-localhost}
ENV MQTT_PORT=${MQTT_PORT:-1883}
ENV MQTT_USERNAME=$MQTT_USERNAME
ENV MQTT_PASSWORD=$MQTT_PASSWORD

RUN : "${SENSORS:?Build argument 'SENSORS' needs to be set and non-empty.}"

RUN apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing/ --allow-untrusted \
rtl-sdr \
mosquitto-libs++ \
zsh

COPY --from=BUILD_ENV /build/sparsnas_decode /usr/bin/
COPY sparsnas.sh /

RUN sed -i "s/^SENSORS=.*/SENSORS=(${SENSORS})/" /sparsnas.sh

ENTRYPOINT ["/sparsnas.sh"]
178 changes: 126 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
**This repository has been retired. Please use alternative forks.**

*******************************************************************


A BIG thanks to the https://www.facebook.com/groups/SHgruppen on Facebook and a special superduper thanks to the core coder @strigeus!
https://github.com/strigeus/sparsnas_decoder

This is a fork is adapted for output in JSON format to a MQTT broker.

[![buy me a coffee](https://www.buymeacoffee.com/assets/img/custom_images/yellow_img.png)](https://www.buymeacoffee.com/tubalainen)

If you want to implement the same thing as below into an ESP8266 please see the following project: https://github.com/bphermansson/EspSparsnasGateway

If you want to get into the bits and bytes of the system please see:
https://github.com/kodarn/Sparsnas

Asif just made a HASSIO Addon based on this code, check out his repository here: https://github.com/asifma/hassio-addons

This is a decoder for IKEA SPARSNÄS.
===================================
Expand All @@ -6,80 +24,136 @@ It uses RTL-SDR running on a Raspberry Pi to demodulate the FSK signal, and deco

The packet data is encrypted using your sender's ID. The sender ID is the last 6 digits of the serial number located under the battery.

How to build:
Prerequisites:
-------------
Tested on a Raspberry Pi 3 with Raspbian Stretch with a NooElec Nano 3 USB SDR dongle. You should be able to use any RTL-SDR compatible dongle. If you live in Sweden/EU the NooElec Micro 3 dongle can be bought from www.amazon.de (free shipping on orders over 25 EUR).
Of get your self the "real deal", an original RTL-SDR v3 from https://www.lohelectronics.se/kommunikation/amatorradio/radio/rtl-sdr-r820t2-rtl2832u-1ppm-tcxo-sma-sdr . Dont forget to make your self an antenna, the IKEA Sparsnäs transmits on 868 MHz so a 1/2 wave lenght wire connected to the center pin in the antenna port should do the trick. Make the wire approximently 16 cm long.

First edit sparsnas_decode.cpp to setup your sender id. Then:
```g++ -o sparsnas_decode -O3 sparsnas_decode.cpp```

An IKEA Sparsnäs unit (duuh)

How to calibrate to your sender frequency:
------------------------------------------
```rtl_sdr -f 868000000 -s 1024000 -g 40 - > sparsnas.raw```
An MQTT broker installed, see this video for support/help to get it going: https://www.youtube.com/watch?v=VaWdvVVYU3A

Wait about 20 seconds. Press Ctrl-C.
You can also pipe your MQTT data via node-red to InfluxDB for diplaying in for example Grafana, @naestrom have done a great job creating a node-red flow, please find more info here: https://github.com/Naesstrom/sparsnas_mqtt_nodered_influxdb

```./sparsnas_decode sparsnas.raw --find-frequencies```

Wait about a minute for it to finish. It prints something like:
The installation:
-------------
It is highly recommended to use the [docker](https://docker.com) version described [here](docker.md).

```#define FREQUENCIES {65050.000000, 105050.000000}```
The following instructions are for you that for some reason don't want to use docker, and assumes a debian or ubuntu based environment.

Edit your sparsnas_decode.cpp with those values and rebuild it according to the How to build step above.
```sh
sudo apt-get update && sudo apt-get install -y git g++ libmosquitto-dev libmosquitto1 rtl-sdr zsh busybox
cd ~
git clone https://github.com/tubalainen/sparsnas_decoder
cd sparsnas_decoder
git checkout dockerVersion

How to run:
-----------
```rtl_sdr -f 868000000 -s 1024000 -g 40 - | ./sparsnas_decode```
# Build sparsnas_decode and copy the binary to /usr/bin
g++ -o sparsnas_decode -std=gnu++11 -O2 sparsnas_decode.cpp -lmosquitto
sudo cp sparsnas_decode /usr/bin/
```
The decoder is now cloned, compiled and copied to `/usr/bin/sparsnas_decoder`


Technical details:
------------------
SPARSNÄS uses a CC1101 chip configured for GFSK modulation at 868MHz. The two FSK symbol frequencies once downconverted to baseband are roughly 67kHz and 105kHz. (EDIT: It seems like with a different RTL-SDR the baseband frequencies are 12.5khz and 50khz. Maybe my first RTL-SDR was inaccurate). The packet length is 18 bytes, including the length byte, and a 16-bit CRC is appended to the end. The CC1101 sync word is 0xD201. The packet payload byte 5 to 17 are encrypted using a key derived from the sender device's ID.
Using your favorite text editor, create a new file named /etc/modprobe.d/no-rtl.conf and put the following text in the file. You need to run that text editor as sudo (i.e. 'sudo vi' or 'sudo nano' etc) to write to the modprobe.d directory:

The encryption key is a repeating XOR key:
```
const uint32_t sensor_id_sub = SENSOR_ID - 0x5D38E8CB;
enc_key[0] = (uint8_t)(sensor_id_sub >> 24);
enc_key[1] = (uint8_t)(sensor_id_sub);
enc_key[2] = (uint8_t)(sensor_id_sub >> 8);
enc_key[3] = 0x47;
enc_key[4] = (uint8_t)(sensor_id_sub >> 16);
````

Packet format (big endian):
```
0: uint8_t length; // Always 0x11
1: uint8_t sender_id_lo; // Lowest byte of sender ID
2: uint8_t unknown; // Not sure
3: uint8_t major_version; // Always 0x07 - the major version number of the sender.
4: uint8_t minor_version; // Always 0x0E - the minor version number of the sender.
5: uint32_t sender_id; // ID of sender
9: uint16_t time; // Time in units of 15 seconds.
11:uint16_t effect; // Current effect usage
13:uint32_t pulses; // Total number of pulses
17:uint8_t battery; // Battery level, 0-100.
```sh
sudo nano /etc/modprobe.d/no-rtl.conf
```
This is how to convert the 'effect' field into Watt:

```
float watt = (float)((3600000 / PULSES_PER_KWH) * 1024) / (effect);
blacklist dvb_usb_rtl28xxu
blacklist rtl2832
blacklist rtl2830
```

Note: Due to how the encryption works, it's possible for two different SPARSNÄS with unique sender_id to confuse each other. When decrypting a packet from sender B with the A key, it's possible that the resulting packet gets a sender_id equal to A, which means A will display incorrectly decrypted data from the B device.
Reboot with the USB dongle installed in one of the USB ports.

Example usage
-------------
Test your dongle
```
rtl_test
```
ludde@raspberrypi ~/sparsnas $ sudo rtl_sdr -f 868000000 -s 1024000 -g 40 - | ./sparsnas_decode
Outcome should look something like this:
```
pi@raspberrypi:~ $ rtl_test
Found 1 device(s):
0: Realtek, RTL2838UHIDIR, SN: 00000001

Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Supported gain values (29): 0.0 0.9 1.4 2.7 3.7 7.7 8.7 12.5 14.4 15.7 16.6 19.7 20.7 22.9 25.4 28.0 29.7 32.8 33.8 36.4 37.2 38.6 40.2 42.1 43.4 43.9 44.5 48.0 49.6
[R82XX] PLL not locked!
Sampling at 1024000 S/s.
Tuned to 868000000 Hz.
Tuner gain set to 40.20 dB.
Sampling at 2048000 S/s.

Info: This tool will continuously read from the device, and report if
samples get lost. If you observe no further output, everything is fine.

Reading samples in async mode...
[2016-12-05 21:29:35] 12711: 362.3 W. 43.339 kWh. Batt 99%.
[2016-12-05 21:29:50] 12712: 362.6 W. 43.341 kWh. Batt 99%.
lost at least 24 bytes
```

How to configure the decoder:
-------------
Take a photo/make a note of your transmitter ID number underneeth the battery lid of the transmitter (not the display. Obmit the 400 and take the remaining six numbers and make a note of them.

Edit sparsnas.sh to setup your sender id. You are allowed to have unlimitied number of senders and the format is `transmitter_id pulses/kWh` followed by a space.

This command will do it for you :smile: (adding the transmitters 722270 and 602064 with 1000/10000 pulses/kWh respectively).

```sh
SENSORS="722270 1000 602064 10000"; sed -i "s/^SENSORS=.*/SENSORS=(${SENSORS})/" sparsnas.sh
```

Test the script:
```sh
./sparsnas.sh
```

To make the decoder report values over MQTT the MQTT variables needs to be configured as follows:

```sh
MQTT_HOST=192.168.x.x MQTT_PORT=1883 MQTT_USERNAME=username MQTT_PASSWORD=password ./sparsnas.sh
```


To make `sparsnas_decoder` run on startup (modify the `MQTT_*` variables according to your configuration and make sure you get the right path (`/home/pi/`) to `sparsnas.sh`)

```sudo nano /etc/rc.local```

```sh
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi

MQTT_HOST=192.168.x.x MQTT_PORT=1883 MQTT_USERNAME=username MQTT_PASSWORD=password /home/pi/sparsnas_decoder/sparsnas.sh

exit 0
```

Check status and traffic on your MQTT broker:
```sh
mosquitto_sub -v -h 192.168.x.x -u username -P password -t '#'
```
Example of outcome:
```json
core-ssh:~# mosquitto_sub -v -h 192.168.x.x -u username -P password -t '#'
sparsnas/602064 {"Sequence": 47318,"Watt": 2424.00,"kWh": 4207.933,"battery": 100,"FreqErr": 0.70,"CRC":"ok","Sensor":602064}
sparsnas/722270 {"Sequence": 77,"Watt": 3245.07,"kWh": 0.483,"battery": 100,"FreqErr": 0.40,"CRC":"ok","Sensor":722270}
```

To configure Home Assistant have a look in the [home-assistant](home_assistant) folder.
22 changes: 22 additions & 0 deletions docker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Docker support instructions


1. Build docker container as follows. The `SENSORS` is required and is the unique
id of your sensors in the form `sensor_id pulses_per_kwh`. The various `MQTT_`args are
optional (but highly recommended to enable communication to your mqtt_broker).

```
docker build -t sparsnas --build-arg SENSORS="1234 1000" \
 --build-arg MQTT_HOST=192.168.x.x --build-arg MQTT_PORT=1883 \
--build-arg MQTT_USERNAME=username --build-arg MQTT_PASSWORD=password \
https://github.com/tubalainen/sparsnas_decoder.git
```

2. Run the container (it is possible to set the arguments above at runtime as
`-e MQTT_HOST=192.168.1.2` if you like).

```
docker run -it --device=/dev/bus/usb --name=sparsnas --restart=always sparsnas:latest
```

3. Sit back and enjoy :smile:.
5 changes: 5 additions & 0 deletions grafana/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Example panel for grafana

The json-file will create a dashboard in grafana that expects data from indluxDB pushed by Home Assistant like the one below.

<img src="sparsnas.png?raw=true" />
Binary file added grafana/sparsnas.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading