WS2812B LED-Stripes and Matrix

Monday, June 24. 2019

I'm rather fond of WS2812B 'Neopixel' led strips and the elgant, minimalistic construction it allows in combination with Nodemcu as the controller. It takes a fat power source (like Meanwell ) connected to the red and white power cables of the strip, on the 3 connections at the data cable of the strip the nodemcu is hooked in with Vin to red, GND to black and the yellow cable to one of  the Nodemcu's data pins. Add a program on the Nodemcu that supports mosquitto, OTA updates and makes use of the FastLED library to control the leds and you are ready to go.

Create your own effects or adapt something open sourced by others - a search on 'ws2812b fastled effect' is a nice start. The prices are moderate, not far from what a Phillips Hue Ledstrip (2m, 36 LED elements) will cost you for 5m of LED strip with 300 Led elements.

Those LED strips come in a number of variants, 30 or 60 (or even 144) leds per meter, IP65 water resistant ones that come with an adhesive back side (an anti-feature for me) and IP67 ones in a silicone tube. The matrix is special, it is a 16cmx16cm plate with 16x16 LEDs mounted on it, connected into a single line that sort of zig-zags over the plate, the first row in a left to right orientation, the second row right to left and then left to right again... You can search and select from the rich supply of 16x16 pixel art left over from console game programming, format the image files to fit with the zig-zag orientation of the matrix and you have a flexible display for retro style icons.

There are some videos on youtube how to create that which I found really helpful even when I ended doing things in a slightly different way. Once everything has been installed and set up the question comes up how to get new icons to display (web search and considerable afterwork) and how to obtain the rgb information for the pic in the correct order. There is another tutorial for that recommending a program lcd-image converter and manually merging rows of pixel data. That program is even available for Arch Linus but unfortunately it crahes a lot. And the manual merging of image data isn't really a viable option.

After some fruitless trials along those lines I came up with my own solution in the form a tiny bash script using image magick's convert which creates an array of rgb values in the right order from a supplied 16x16 .bmp file.


#!/bin/bash

# convert banane.bmp rgb:- | xxd -g3 -c48

#echo $0 $1

`convert $1 rgb:- | xxd -g3 -c48 > ccxx.tmp`

t=0

input="./ccxx.tmp"
while IFS= read -r line
do
  a=( $line )
  var=$((var+1))
  #echo "$line"
  if (( $var % 2 )); then
     echo 0x${a[16]}, 0x${a[15]}, 0x${a[14]}, 0x${a[13]}, 0x${a[12]}, 0x${a[11]}, 0x${a[10]}, 0x${a[9]}, 0x${a[8]}, 0x${a[7]}, 0x${a[6]}, 0x${a[5]}, 0x${a[4]}, 0x${a[3]}, 0x${a[2]}, 0x${a[1]},
  else
     echo 0x${a[1]}, 0x${a[2]}, 0x${a[3]}, 0x${a[4]}, 0x${a[5]}, 0x${a[6]}, 0x${a[7]}, 0x${a[8]}, 0x${a[9]}, 0x${a[10]}, 0x${a[11]}, 0x${a[12]}, 0x${a[13]}, 0x${a[14]}, 0x${a[15]}, 0x${a[16]},
  fi
done < "$input"
 

The process is not perfect though, for some reason the colors often turn out quite different on the lcd display than what they looked on the monitor and I ended with several loops of edit and copy again. I'll end this with 3 pixel arrays as a bonus:

const long herz[]  =
{
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x330000, 0xcc0000, 0xcc0000, 0x330000, 0x000000, 0x000000, 0x000000, 0x000000, 0x330000, 0xcc0000, 0xcc0000, 0x330000, 0x000000, 0x000000,
0x000000, 0x660000, 0xcc3333, 0xcc3333, 0xcc0000, 0xcc0000, 0x660000, 0x000000, 0x000000, 0x660000, 0xcc0000, 0xcc0000, 0xcc0000, 0xcc0000, 0x330000, 0x000000,
0xcc0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xcc0000, 0x990000, 0x660000, 0xcc0000, 0xff0000, 0xff3333, 0xffcccc, 0xffffff, 0xcc3333, 0x330000,
0xcc0000, 0xcc3333, 0xffcccc, 0xff3333, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000,
0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xcc0000, 0xcc0000,
0x330000, 0xcc0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xcc0000, 0x000000,
0x000000, 0x000000, 0xcc0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xcc0000, 0x330000, 0x000000,
0x000000, 0x000000, 0x330000, 0xcc0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xcc0000, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0x000000, 0xcc0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xcc0000, 0x330000, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0x000000, 0x330000, 0xcc0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xcc0000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xcc0000, 0xff0000, 0xff0000, 0xcc0000, 0x330000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x330000, 0xcc0000, 0xcc0000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xff0000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000
};

const long cool_smiley[]  =
{
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x332001, 0x835601, 0xa87204, 0xa57005, 0x7f5601, 0x271700, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0x472e00, 0xc28814, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xc28916, 0x4d3201, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x694602, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0x634102, 0x000000, 0x000000,
0x000000, 0x402800, 0xb77a08, 0xb77a08, 0xb77b08, 0xb57804, 0xb57804, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0x4d3201, 0x000000,
0x000000, 0xb8841a, 0xa29878, 0x807342, 0x9e843a, 0x9f863e, 0xa38c45, 0xb67a07, 0xb67a07, 0xa18b47, 0x9e853d, 0x9e853d, 0x8b815d, 0xa49b7f, 0xb88114, 0x000000,
0x543906, 0x685932, 0x6b6553, 0x31280f, 0x31280f, 0x31280f, 0x31280f, 0x31280f, 0x342b13, 0x31280f, 0x31280f, 0x31280f, 0x31280f, 0x000000, 0x4f4220, 0x503907,
0x5a3d02, 0xbdad7f, 0x000000, 0x000000, 0x31280f, 0x31280f, 0x31280f, 0xb77a08, 0xb77a08, 0x000000, 0x000000, 0x31280f, 0x31280f, 0x31280f, 0xb77a08, 0x986702,
0xb97b04, 0xb77a08, 0x716330, 0x000000, 0x000000, 0x000000, 0x473f28, 0xb77a08, 0xb77a08, 0x473f28, 0x000000, 0x000000, 0x000000, 0x473f28, 0xc28814, 0xc28814,
0xc28814, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb47804,
0x986702, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0x5c3e02,
0x452e01, 0xb77a08, 0xb77a08, 0xb77a08, 0x473f28, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0x473f28, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0x402800,
0x000000, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0x473f28, 0x473f28, 0xb77a08, 0xb77a08, 0xb77a08, 0x473f28, 0x473f28, 0xb77a08, 0xb77a08, 0xc38b18, 0x000000,
0x000000, 0x5c3d02, 0xb77a08, 0xb77a08, 0xb77a08, 0x473f28, 0x473f28, 0x473f28, 0x473f28, 0x473f28, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0x4d3201, 0x000000,
0x000000, 0x000000, 0x694602, 0xc28814, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0x694602, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0x533802, 0xc48c18, 0xb77a08, 0xb77a08, 0xc28814, 0xb77a08, 0xb77a08, 0xb77a08, 0xb77a08, 0x4d3201, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x472e00, 0xa16d03, 0xbd7f04, 0xbd7f04, 0xa56f03, 0x533802, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000
  };


const long om[]  =
{

0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x8a0001, 0x900001, 0x050000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x3b0000, 0x5f0000, 0x000000, 0xef0002, 0xee0002, 0x000000, 0x1f0000, 0x290000, 0x000000, 0x000000,
0x000000, 0x2c0000, 0xbe0001, 0xc20001, 0x000000, 0x000000, 0x000000, 0x950001, 0xc40001, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
0x000000, 0x000000, 0x320000, 0x860001, 0xb70001, 0xc80001, 0x990001, 0x000000, 0xeb0002, 0xd70001, 0xd40001, 0xea0002, 0xfa0002, 0xed0002, 0x770000, 0x000000,
0x000000, 0x000000, 0x000000, 0x000000, 0xea0002, 0xf00002, 0xe50002, 0x000000, 0x4e0000, 0xfa0002, 0xfa0002, 0xfa0002, 0xf60002, 0xcf0001, 0x460000, 0x000000,
0x000000, 0x340000, 0xd30001, 0xf70002, 0xdf0002, 0x770000, 0xd90001, 0xf30002, 0x750000, 0x000000, 0x000000, 0x000000, 0xd60001, 0xb80001, 0x4e0000, 0x000000,
0x340000, 0xc70001, 0xda0001, 0xe90002, 0xfa0002, 0xe50002, 0x000000, 0x4e0000, 0xe60002, 0x6c0000, 0x000000, 0x000000, 0x8b0001, 0x6b0000, 0x000000, 0x000000,
0x000000, 0x000000, 0x000000, 0x000000, 0x770000, 0xa10001, 0xd40001, 0xc80001, 0x2b0000, 0xc20001, 0xfa0002, 0xe50002, 0x6c0000, 0x260000, 0xbf0001, 0x770000,
0xbf0001, 0x9d0001, 0x000000, 0x000000, 0x940001, 0xf40002, 0xf30002, 0x9a0001, 0x7f0000, 0xe90002, 0xfa0002, 0xe80002, 0x520000, 0x000000, 0x000000, 0x370000,
0x970001, 0x000000, 0x000000, 0x030000, 0xab0001, 0xe80002, 0xf00002, 0xf00002, 0xe80002, 0xe00002, 0xab0001, 0x1e0000, 0x000000, 0x000000, 0xa20001, 0xcf0001,
0xcb0001, 0xd30001, 0x380000, 0x000000, 0x000000, 0x000000, 0x000000, 0xc70001, 0xe60002, 0x740000, 0x000000, 0x1f0000, 0x000000, 0x000000, 0x6f0000, 0xb30001,
0x9f0001, 0xbb0001, 0x0f0000, 0x000000, 0x000000, 0x000000, 0x000000, 0xca0001, 0xe10002, 0x000000, 0xc30001, 0x6a0000, 0x000000, 0xc80001, 0xf80002, 0x770000,
0x000000, 0xf10002, 0xfa0002, 0xf40002, 0xf20002, 0xf10002, 0x000000, 0xe20002, 0xe50002, 0x6a0000, 0x060000, 0x010000, 0x3b0000, 0x9e0001, 0xe20002, 0x600000,
0x050000, 0xae0001, 0xf40002, 0xe10002, 0xcd0001, 0xd00001, 0xea0002, 0xfa0002, 0xc60001, 0x310000, 0xbe0001, 0xf70002, 0xfa0002, 0xf20002, 0x4e0000, 0x130000,
0x000000, 0x190000, 0x000000, 0x9d0001, 0x870001, 0x310000, 0x000000, 0x000000, 0xe10002, 0xfa0002, 0xfa0002, 0xfa0002, 0xf40002, 0xba0001, 0x330000, 0x000000,
0x000000, 0x000000, 0x1e0000, 0x4e0000, 0xba0001, 0xc70001, 0xb10001, 0x4e0000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000

};

 

 

 

rfid-tags for presence detection in smarthome

Wednesday, November 28. 2018

Pressence detection is vital in a smarthome setup, lights should go out when I leave and on when I come home.  But presence detection is not trivial, you can not rely on PIR motion sensors since they often do false positives. You can not rely on pinging the smartphone when it connects to the WLAN because phones have sleep modes to save energy and you'll find your phone regarded as absent when it sits next to you on your desk. Even owntracks and tasker provide solutions which work sometimes and fail later. .

And, more often then I like, I have to search for my keys before leaving the house. Now this is how I try to catch two flies with one stone:

I bought a RC522 rfid reader to integrate it into my smarthome IoT.
Most of the stuff you can find for those, both software and things, follows the idea of access control.
That is:

  • the thing with the reader waits in front of a door and controls a lock. User comes, holds a keycard at the reader, is denied or allowed, puts the keycard back in their pocket and enters...

My use case is different, more like what you may find in a hotel:

  • the thing with the reader waits behind the door and the user is supposed to insert the key card into the reader and leave it there. The reader identifies the key card and informs the smarthome controler that the owner of that key card is at home so it's time to turn on the lights and enable all the features that will be turned off again when the key card is taken out of the reader, later.

For this to work the key card (those blue drop shaped ones with a key chain ring you get with the reader) has to be in close range of the reader in a stable position, in other words, some sort of pocket is needed.

 

rfid-boxThe box is a remix of something I found searching thingiverse and sits at https://www.thingiverse.com/thing:3242266

It's printed in fast mode and with elements into all directions the slicer added lots of support which was hard to get off, you can see ht the box suffered from it.

Anyways, this cheap RC522 rfid reader which set me back by about 6€ sits in this box I printed, with a pocket to insert the chip and thus hold my keys at a defined place. The reader, connected to an Nodemcu V2 microcontroller identifies the chip, thus knows it's me who is at home and reports this to the smarthome controller. When I leave the house and take my keys the reader creates a new event and the system knows I'm out.

On the software side again there are plenty of example sketches for access control where the reader idles until you put a key card in its range, then the card is analysed, the result is given and the thing idles on. There is no event when the card is taken away.

So I had to write my own sketch for that, too. Again it is a remix.
It runs on an arduino clone and it creates an event when a known key card is entered, and another event when that card is taken out.

Since my smarthome is controlled by openHab2 which has a very usable rest api there is some code to report those events to it.
The sketch is part of the thingiverse file bundle linked above.

(Page 1 of 1, totaling 2 entries)