Category Archives: IOT / Domoticz

i2c and cap1188 Musical instrument (from vga to esp32?)

Way back in 2018 i was playing around with i2c and touch.

CAP1188 Multi touch sensor



I remembered that VGA was using i2c to get information from monitors like brand/type and connection information.

I managed to access the cap1188 up to my Laptop via VGA.

2018 Schematic i used to abuse vga …

The final python code i used to play with the variables and playing sound i can’t find.
But below is the test code

#!/usr/bin/python

# NOTE: i did a address scan, now i have 3v3 connected to AD, so probably the address is 0x28 !!

import smbus

bus = smbus.SMBus(1)    # 0 = /dev/i2c-0 (port I2C0), 1 = /dev/i2c-1 (port I2C1)

DEVICE_ADDRESS = 0x29      
DEVICEx = 0x10      
DEVICE_REG_MODE1 = 0x00
DEVICE_REG_LEDOUT0 = 0x1d

#Write a single register
bus.write_byte_data(DEVICE_ADDRESS, 0x1f, 0x3F)

#Write an array of registers
#ledout_values = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
#bus.write_i2c_block_data(DEVICE_ADDRESS, DEVICE_REG_LEDOUT0, ledout_values)
while True:

        print bus.read_byte_data(DEVICE_ADDRESS,0x10), bus.read_byte_data(DEVICE_ADDRESS,0x11) , bus.read_byte_data(DEVICE_ADDRESS,0x12), bus.read_byte_data(DEVICE_ADDRESS,0x13), bus.read_byte_data(DEVICE_ADDRESS,0x14), bus.read_byte_dat
a(DEVICE_ADDRESS,0x15), bus.read_byte_data(DEVICE_ADDRESS,0x16), bus.read_byte_data(DEVICE_ADDRESS,0x17)

Today i connected the cap1188 to a ESP32 and a piezo buzzer.

/*** Based on below library ***/
/*** Changed pins and added sound ***/

/*************************************************** 
  This is a library for the CAP1188 I2C/SPI 8-chan Capacitive Sensor

  Designed specifically to work with the CAP1188 sensor from Adafruit
  ----> https://www.adafruit.com/products/1602

  These sensors use I2C/SPI to communicate, 2+ pins are required to  
  interface
  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/
 
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_CAP1188.h>

const int TONE_OUTPUT_PIN = 26;
const int TONE_PWM_CHANNEL = 0; 
int freq = 0;


// Reset Pin is used for I2C or SPI
#define CAP1188_RESET  9

// CS pin is used for software or hardware SPI
#define CAP1188_CS  10

// These are defined for software SPI, for hardware SPI, check your 
// board's SPI pins in the Arduino documentation
#define CAP1188_MOSI  11
#define CAP1188_MISO  12
#define CAP1188_CLK  13

// For I2C, connect SDA to your Arduino's SDA pin, SCL to SCL pin
// On UNO/Duemilanove/etc, SDA == Analog 4, SCL == Analog 5
// On Leonardo/Micro, SDA == Digital 2, SCL == Digital 3
// On Mega/ADK/Due, SDA == Digital 20, SCL == Digital 21

// Use I2C, no reset pin!
Adafruit_CAP1188 cap = Adafruit_CAP1188();

// Or...Use I2C, with reset pin
//Adafruit_CAP1188 cap = Adafruit_CAP1188(CAP1188_RESET);

// Or... Hardware SPI, CS pin & reset pin 
// Adafruit_CAP1188 cap = Adafruit_CAP1188(CAP1188_CS, CAP1188_RESET);

// Or.. Software SPI: clock, miso, mosi, cs, reset
//Adafruit_CAP1188 cap = Adafruit_CAP1188(CAP1188_CLK, CAP1188_MISO, CAP1188_MOSI, CAP1188_CS, CAP1188_RESET);

void setup() {
  Serial.begin(9600);
  Serial.println("CAP1188 test!");
  ledcAttachPin(TONE_OUTPUT_PIN, TONE_PWM_CHANNEL);
 

  // Initialize the sensor, if using i2c you can pass in the i2c address
  if (!cap.begin(0x28)){
  //if (!cap.begin()) {
    Serial.println("CAP1188 not found");
    while (1);
  }
  Serial.println("CAP1188 found!");
}

void loop() {
  uint8_t touched = cap.touched();

  if (touched == 0) {
    // No touch detected
    return;
  }
  
  for (uint8_t i=0; i<8; i++) {
    if (touched & (1 << i)) {
      Serial.print(touched); Serial.print("\t");
      freq = (i * 100);
      ledcWriteTone(TONE_PWM_CHANNEL, freq);
      delay(100);
    }
  }

  Serial.println();
  delay(50);
}

Finding the right pins or above pinout was the hardest part.
The sketch reads the pins binary so value 129 is first and last bit.

Now i have to get the sound sounding a little better and add frequencies and fingersettings to the sketch to get a minimal electronic bagpipe. (V3 it is .. )

To be continued ..

Micropython and TFT display test environment

This exercise is to get a micropython dev environment with a graphical display.

pip3 install esptool adafruit-ampy

Erase board (use correct tty device!)

esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash

Flash using

esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x1000 esp32-20190125-v1.10.bin

Download from https://micropython.org/resources/firmware/esp32-20220618-v1.19.1.bin

Test with

screen /dev/ttyUSB0 115200

Enter
import machine
or
help()

Great up and running

Now we have to install a boot loader
Use ampy to list files

#list boot
ampy -p /dev/ttyUSB0 ls 
/boot.py

#get boot.py
ampy -p /dev/ttyUSB0 get boot.py

vi boot.py (create new)

#import esp
#esp.osdebug(None)
#import webrepl
#webrepl.start()

def connect():
    import network
    sta_if = network.WLAN(network.STA_IF)
    if not sta_if.isconnected():
        print('connecting to network...')
        sta_if.active(True)
        sta_if.connect('WIFISSID', 'WIFIPASS')
        while not sta_if.isconnected():
            pass
    print('network config:', sta_if.ifconfig())

Push the file

ampy -p /dev/ttyUSB0 put boot.py
Usage: ampy [OPTIONS] COMMAND [ARGS]...

  ampy - Adafruit MicroPython Tool

  Ampy is a tool to control MicroPython boards over a serial connection.
  Using ampy you can manipulate files on the board's internal filesystem and
  even run scripts.

Options:
  -p, --port PORT    Name of serial port for connected board.  Can optionally
                     specify with AMPY_PORT environment variable.  [required]
  -b, --baud BAUD    Baud rate for the serial connection (default 115200).
                     Can optionally specify with AMPY_BAUD environment
                     variable.
  -d, --delay DELAY  Delay in seconds before entering RAW MODE (default 0).
                     Can optionally specify with AMPY_DELAY environment
                     variable.
  --version          Show the version and exit.
  --help             Show this message and exit.

Commands:
  get    Retrieve a file from the board.
  ls     List contents of a directory on the board.
  mkdir  Create a directory on the board.
  put    Put a file or folder and its contents on the board.
  reset  Perform soft reset/reboot of the board.
  rm     Remove a file from the board.
  rmdir  Forcefully remove a folder and all its children from the board.
  run    Run a script and print its output.

Connect to serial console using screen

sudo screen /dev/ttyUSB0 115200
(use CTRL-A \ to exit)

Connect to wifi

import boot
connect()

Led blinky test, with below file named ledtest.py

import time
from machine import Pin
led=Pin(2,Pin.OUT)        #Internal led pin

while True:
  led.value(1)            #Set led turn on
  time.sleep(0.5)
  led.value(0)            #Set led turn off
  time.sleep(0.5)

Upload and run script

ampy -p /dev/ttyUSB0 put ledtest.py
import ledtest (without .py!)

Next todo: boot.py @boot ?!?
Run custom python after booting.
Connect display and play with drawing.

Tip: Install rshell !

sudo pip3 install rshell
fash@zspot:~$ rshell 
Welcome to rshell. Use Control-D (or the exit command) to exit rshell.

No MicroPython boards connected - use the connect command to add one

/home/fash> autoconnect: /dev/ttyUSB0 action: add

/home/fash> ?

Documented commands (type help <topic>):
========================================
args    cat  connect  date  edit  filesize  help  mkdir  rm     shell
boards  cd   cp       echo  exit  filetype  ls    repl   rsync

Use Control-D (or the exit command) to exit rshell.

Connecting the display

I’ve connected the display as above. Note the different connections on the display. Above fritzing part has connections for touch screen!
The 4 or 5 pins on the other side are for sdcard functionallity.

display       esp
-----------------
SDO/MISO      D19
LED           VIN (5v)
SCK           D18
SDI/MOSI      D23
DC/RS         D15
RESET         D14
CS            D5
GND           GND
VCC           3.3V

Not my different ESP, gpio has high numbers and only 30 pins.
Most ESP have 2 SPI controllers. Check yours!

Software part

git clone https://github.com/rdagger/micropython-ili9341

Next create a setupmydisplay.py file, and edit your pin connections

from ili9341 import Display
from machine import Pin, SPI

TFT_CLK_PIN = const(18)
TFT_MOSI_PIN = const(23)
TFT_MISO_PIN = const(19)

TFT_CS_PIN = const(5)
TFT_RST_PIN = const(14)
TFT_DC_PIN = const(15)

def createMyDisplay():
    #spi = SPI(0, baudrate=40000000, sck=Pin(TFT_CLK_PIN), mosi=Pin(TFT_MOSI_PIN))
    spiTFT = SPI(2, baudrate=51200000,
                 sck=Pin(TFT_CLK_PIN), mosi=Pin(TFT_MOSI_PIN))
    display = Display(spiTFT,
                      dc=Pin(TFT_DC_PIN), cs=Pin(TFT_CS_PIN), rst=Pin(TFT_RST_PIN))
    return display

Now you can use the library by editing a example like demo_bouncing_boxes.py

Add and change

# At the beginning of the file
import setupmydisplay.py

Futher down comment two lines and add your own setup

        # Baud rate of 40000000 seems about the max
        #spi = SPI(1, baudrate=40000000, sck=Pin(14), mosi=Pin(13))
        #display = Display(spi, dc=Pin(4), cs=Pin(16), rst=Pin(17))
        display = setup.createMyDisplay()

Upload to ESP32 and testing!

ampy -p /dev/ttyUSB0 put demo_bouncing_boxes.py
ampy -p /dev/ttyUSB0 put setupmydisplay.py
# connect and start
sudo screen /dev/ttyUSB0 115200
import demo_bouncing_boxes.py

Race track Controller

I got a vintage racetrack from a colleage a while back.

In the past i had some ideas controlling train or race tracks.
For train tracks i wanted to write intelligent maneuver software.
For a racetrack a web controllable race. Maybe with a webcam mounted on the car??

L298N – DC motor controller

So i bought a little DC motor controller (2 channels) and took a esp32.

ESP: 
GPIO04 Player1 IN1 
GPIO05 Player1 IN2
GPIO19 Player2 IN1 
GPIO18 Player2 IN2
GPIO13 PWM Player1
GPIO14 PWM Player2

The webinterface is behind a reverse proxy (apache)

TO BE POSTED .. arduino code

<VirtualHost *:443>
   SSLEngine on
   SSLProxyEngine On

   SSLProtocol all -SSLv2 -SSLv3 +TLSv1
   SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:!RC4+RSA:+HIGH:+MEDIUM

   SSLCertificateFile /etc/ssl/.......cer
   SSLCertificateKeyFile /etc/ssl/private/........key
   SSLCertificateChainFile /etc/ssl/private/GlobalSignRootCA.cer
   SSLCertificateChainFile /etc/ssl/private/AlphaSSLCA-SHA256-G2.cer

   CustomLog /var/log/httpd/media_ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"


    ServerAdmin webmaster@henriaanstoot.nl
    ServerName race.henriaanstoot.nl

ProxyRequests Off
ProxyPreserveHost On
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off

<Location />
ProxyPass  http://10.1.0.25/
ProxyPassReverse  http://10.1.0.25/
</Location>

    ErrorLog /var/log/httpd/race.henriaanstoot.nl-error.log
    CustomLog /var/log/httpd/race.henriaanstoot.nl-access.log combined
</VirtualHost>

Arduino IDE

Adding boards:

File > Preferences > Additional Boards
Add url (comma separated)
Press OK

ESP32 :

https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

ATTINY85:

https://arduino.esp8266.com/stable/package_esp8266com_index.json,https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json

After that go to the Board manager.
Tools > Board: ..... > Board Manager
Search board, click and install.
NOTE: Some sketches require a specific version!

Select your board, and write/open you sketch.

First thing to do is test compiling your sketch

Press the little button on the left

Libraries:

When you get a compile error like below, you are missing those libraries

Goto tools > Manage libraries

Search for your needed library, sometimes there are multiple which look alike. This is a trial and error approach.
Sometimes it doesn’t exists and you need to upload a zip containing the library. (Sketch > Include Library > Add .zip library

Downloading a zip containing the library
Adding the library zip file

When looking at the first lines of you sketch, there are include statements like:

#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>

But sometimes there are statements without the < > characters.
Then it will be a included file just for your sketch.

Note the second tab MPU6050x.h which contains specific code only for this sketch.

Redo a test recompile using the tic icon again.

Everything okay? .. Select the correct port in Tools > Port
And press the Arrowright icon to upload/flash.
Note: sometimes you have to hold a button or press a little flash button on your device to flash.

esptool.py v3.3
Serial port COM8
Connecting.....
Chip is ESP32-D0WDQ6-V3 (revision 3)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: c8:c9:a3:f9:02:d0
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 921600
Changed.
Configuring flash size...
Flash will be erased from 0x00001000 to 0x00005fff...
Flash will be erased from 0x00008000 to 0x00008fff...
Flash will be erased from 0x0000e000 to 0x0000ffff...
Flash will be erased from 0x00010000 to 0x000c7fff...
Flash params set to 0x022f
Compressed 18880 bytes to 12992...
Writing at 0x00001000... (100 %)
Wrote 18880 bytes (12992 compressed) at 0x00001000 in 0.3 seconds (effective 482.8 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 128...
Writing at 0x00008000... (100 %)
Wrote 3072 bytes (128 compressed) at 0x00008000 in 0.0 seconds (effective 627.7 kbit/s)...
Hash of data verified.
Compressed 8192 bytes to 47...
Writing at 0x0000e000... (100 %)
Wrote 8192 bytes (47 compressed) at 0x0000e000 in 0.1 seconds (effective 1087.9 kbit/s)...
Hash of data verified.
Compressed 750976 bytes to 477779...
Writing at 0x00010000... (3 %)
...
...
...
Writing at 0x000bb633... (93 %)
Writing at 0x000c0acd... (96 %)
Writing at 0x000c6649... (100 %)
Wrote 750976 bytes (477779 compressed) at 0x00010000 in 6.3 seconds (effective 947.4 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

Most of the boards you can connect via micro-usb.
Sometimes you need adaptors like:

TIPS ‘n tricks:

Open same file in another editor, so you can compare for example the top (declarations) and futher down the code.
Else you could be ending up scolling up/down all day long. And probably forgetting how a variablename was exacly spelled.

Use serial monitor!
When debugging this is a valuable tool.
Enter statements into you code, which prints debugging info to a serial monitoring window when your device is still hookedup to your PC.

Example printing connected IP and values registered
You even can use serial plotting!!

How to print?

void setup(){
  Serial.begin(115200);
  ... code 
  Serial.println("Connecting...");
  ... code
  Serial.println(WiFi.localIP());

  or 

  Serial.println(measuredvalue);

Other obvious tips:
Add comment lines (documentation)
Use variable names which make sense!
( Hard to find what aaaa() does, or what tmp-a is, but
LastTempValue says a lot more)

MCH2022 Badge

Almost … friday will be the day i’ll attend May Contain Hackers.
Besides the awesome villages and talks.

UPDATE: 20220727
UPDATE: 20220812

You get a hackable badge, this one is more amazing as previous versions.

I can’t wait to have a go at this cool gadget. I personally could do without the pcb fancy design.

  • Espressif ESP32 Wrover-E with 16MB of flash storage and paired with 8MB of PSRAM, for front-end badge computing and compatibility with the badge.team ecosystem back to the 2017 SHA badge.
  • Lattice ICE40UP5K FPGA for hardware-accelerated graphics and user FPGA hardware designs.
  • Raspberry Pi RP2040 for advanced USB communication and board management.
  • 2Ah LiPo battery to give you a full day of fun on a charge.
  • 16-bit DAC with stereo output to headphone socket, onboard mono speaker.
  • ILI9341 2.2 inch TFT display with a 240 by 320 pixel resolution.
  • Bosch BNO055 orientation sensor.
  • Bosch BME680 environmental sensor.
  • The usual array of addressable LEDs.
  • SAO and Qwiic expansion connectors, FPGA PMOD expansion, plus onboard prototyping area.

Downloadable apps, micro python, Arduino ide programming.
All kinds of GPIO pins, leds buttons, sound.
Check out https://hatchery.badge.team/

You can play with this virtually here!
https://wokwi.com/projects/335445228923126356

So much potential! Great start for a DIY project.

I won’t post about the workings, thats all well documented online.
I shall post about the hacks/findings i personally did.

UPDATE: 20220727
Made a micropython program to keep your NameTag level to the ground (Better version)

UPDATE: 20220812

Someone made a 8bit logic analyser using the pmod connector !

Screens and DIY projects

Below some examples and connection diagrams to control displays.
More code and complete schematics will be added on this page or on a separate projects page.

UPDATE 20230119 Cost of 20×4 display in 1998

LCD

I’ve used a LCD display like this (HITACHI HD44780) on my PC in the 90s, and also written code to use this as a monitoring device on my amiga.

On Linux i used LcdProc – This module also was equiped with a serial connector
Now (2023) it is 8 euros!
When bought now fl to euro 98 Euro or 107 $
;LCD Display Module             Parallel port
;        1 Vss                  20 GND
;        2 Vdd                  14 +5V
;        3 Vlc                  20 GND (contrast LCD display)
;        4 RS (register select) 11 BUSY
;        5 R/W                  12 POUT
;        6 E (enable)           13 SEL
;        7 DB0                   2 D0
;        8 DB1                   3 D1
;        9 DB2                   4 D2
;       10 DB3                   5 D3
;       11 DB4                   6 D4
;       12 DB5                   7 D5
;       13 DB6                   8 D6
;       14 DB7                   9 D7
Amiga code part
        bsr     initprt         ; CIA 8520 init
        bsr     initlcd         ; init lcd display module
        move.l  #0,d0
        rts

initprt:move.b  #$ff,$bfe301    ; parallel port is output
        move.b  $bfd200,d0
        ori.b   #$07,d0         ; select, p-out and busy
        move.b  d0,$bfd200      
        rts

initlcd:move.w  #$38,d0         ; multiple reset
        bsr     send
        bsr     delay2
        move.w  #$38,d0
        bsr     send
        bsr     delay2
        move.w  #$38,d0         ; 2*8 lines
        bsr     send
        bsr     delay2
        move.w  #$01,d0         ; clear display
        bsr     send
        bsr     delay2          ; wait
        move.w  #$0c,d0         ; display on
        bsr     send
        move.w  #$06,d0         ; Entry Mode Set
        bsr     send
        rts

send:   bsr     delay
        btst    #8,d0           ; test rs bit
        beq     reg0
        bsr     rs1             ; select register 1
        bra     skip
reg0:   bsr     rs0             ; select register 0
skip:
        bsr     delay
        bsr     rw0             ; read/write=0 
        bsr     delay
        bsr     e1              ; enable = 1
        bsr     delay
        move.b  d0,$bfe101      ; push data
        bsr     delay
        bsr     e0              
        bsr     delay
        rts

delay:  move.w  #$20,d1
dloop:  subi    #1,d1
        bne     dloop
        rts

delay2: move.w  #$800,d1
dloop2: subi    #1,d1
        bne     dloop2
        rts
Part of my MQTT display alarm thingy
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>  
LiquidCrystal_I2C lcd(0x27, 20, 4);
const char* ssid = "MYACCESSPOINT";
const char* password = "MYPASSWORD";
const char* mqtt_server = "mymqttserver";
const byte ledRed = 12;
const byte horn = 13;
int button = 2;
int press = 0;
boolean buttonToggle = true;


// Todo : DISPLAY 2ND LINE, DISPLAY SILENT, ...

WiFiClient espClient;
PubSubClient client(espClient);
bool toggle = false;
void setup_wifi() {
  delay(100);

  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  randomSeed(micros());
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length)
{
  if (length > 0) {
    toggle = true;
  }

  if (length == 0) {
    toggle = false;
  }

  Serial.print("Command from MQTT broker is : [");
  Serial.print(topic);

  Serial.println();
  Serial.print(" publish data is:");
  lcd.clear();
  lcd.backlight(); // turn off backlight

  {
  
    for (int i = 0; i < length; i++)
    {
      Serial.print((char)payload[i]);
      if (i < 16){
      lcd.setCursor(0, 0);
      lcd.setCursor(i, 0);
      } else {
      lcd.setCursor(0, 1);
      lcd.setCursor(i-16, 1);
      }
      lcd.write((char)payload[i]);
    }
  }


  Serial.println();
} 

void reconnect() {
  
  while (!client.connected())
  {
    Serial.print("Attempting MQTT connection...");
    
    String clientId = "mqttlcd";
    clientId += String(random(0xffff), HEX);

    if (client.connect(clientId.c_str()))
    {
      Serial.println("connected");

      client.subscribe("mqttlcd/message");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(6000);
    }
  }
} 

void setup() {
  Serial.begin(115200);
  pinMode(button, INPUT);
  digitalWrite(2, HIGH);
  pinMode(ledRed, OUTPUT);
  digitalWrite(ledRed, LOW);
  pinMode(horn, OUTPUT);
  digitalWrite(horn, LOW);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  lcd.init(); 
  lcd.backlight();
}

void loop() {

  
  if (!client.connected()) {
    reconnect();
  }
  if (toggle == true) {
    digitalWrite(ledRed, HIGH);
    digitalWrite(horn, HIGH);
    delay(200);
    digitalWrite(ledRed, LOW);
    digitalWrite(horn, LOW);
    delay(200);
  }
  if (toggle == false) {
    digitalWrite(ledRed, LOW);
    digitalWrite(horn, LOW);

  }

  client.setCallback(callback);
  client.loop();

  press = digitalRead(button);
  if (press == LOW)
  {
    if (buttonToggle)
    {
      digitalWrite(ledRed, HIGH);
      digitalWrite(horn, HIGH);
      buttonToggle = !buttonToggle;
    }
    else
    {
      digitalWrite(ledRed, LOW); 
      digitalWrite(horn, LOW);
      buttonToggle = !buttonToggle;
      toggle = false;
      client.publish("mqttlcd/button","pressed");
      lcd.clear();
      lcd.noBacklight(); // turn off backlight
    }
  }
  delay(500);  //delay for debounce
}

Oled

There are several oled displays, mostly controllable with i2c but some of them are SPI

SSD1306 – I2c connected

Using a wemos – Octoprint project for example
Octoprint (Note: this is NOT a multicolor display 1/4 of the display is yellow. )
My notification watch. Runs on a ESP12F connects to Wifi, has a piezo sound element
Using a raspberry (Part of my Lab Sensors Project)
pip3 install adafruit-circuitpython-ssd1306
git clone https://github.com/adafruit/Adafruit_Python_SSD1306 (old)
Edit file - comment SPI section

Some arduino’s have embedded displays like those i’ve used for a Lora project.

Other means of connecting : SPI

SPI connected display

Nextion

Nextion is a Human Machine Interface (HMI) solution combining an onboard processor and memory touch display with Nextion Editor software for HMI GUI project development.

Using the Nextion Editor software, you can quickly develop the HMI GUI by drag-and-drop components (graphics, text, button, slider, etc.) and ASCII text-based instructions for coding how components interact on the display side.

Nextion HMI display connects to peripheral MCU via TTL Serial (5V, TX, RX, GND) to provide event notifications that peripheral MCU can act on, the peripheral MCU can easily update progress, and status back to Nextion display utilizing simple ASCII text-based instructions.

My nextion domoticz box, tilt to wakeup
Domoticz controller

My biltong box using a Nextion

Raspberry displays

 3.5inch RPi Display – 480×320 Pixel – XPT2046 Touch Controller
edit cmdline.txt
add "fbcon=map:10 fbcon=font:ProFont6x11 logo.nologo"
at the end
edit config.txt
add between custom comments at the bottom
dtoverlay=piscreen,speed=24000000,rotate=90
# Or check http://www.lcdwiki.com/3.5inch_RPi_Display

Above display’s i’ve used for Picore Players and the Lidar POC

To try: Getting above display running with a arduino
https://github.com/PaulStoffregen/XPT2046_Touchscreen

Raspberry HDMI display

Easiest of them all, just connect with HDMI, there is a adaptor for hdmi-hdmi (versions 1,2,3) and hdmi-mini-hdmi for RPi4 variants.

Epaper and 7-Segment displays

Other means of displaying information are for example

Epaper

ESP with epaper module, disconnected power for a while, artifacts appear.

7 Segment displays

I used a lot of 7-Segment display’s in the past. They look cool and are hardcore.

My homebrew computer uses this

Nixie tubes!

And there are https://en.wikipedia.org/wiki/Nixie_tube .. I’ve never had those

Above bigger 2D display i used with Wled and a digital microphone, so its sound reactive. The lower part i got in recently .

inmp441 digital microphone

Morse with a ATTINY85

Using above schematic and attiny program you can make a mini morse trainer. It runs on a single CR2032!

I’ve got a attiny85 programmer as pictured below.

A Attiny85 chip is a 8 pin microcontroller, but with far less pin’s and its most of the times just a DIP/DIL (Dual in line)

When using the Arduino IDE:

  • Preferences : Add board url :
    https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json
  • Set board info like: (NOTE PROGRAMMER USBasp)
  • Burn bootloader
  • After that compile and upload

Source code used: https://github.com/andyhighnumber/Attiny-Arduino-Games/tree/master/MorseAttinyArcade

I had to short JP2 to get the USBasp into slow burn mode, else the attiny85 could not be found

Hard to do without a propper morse key!

Photo timelapse slider fixed

I got my DIY timelapse slider out of storage, and notished it wasn’t working any more.
I’t was a quick and dirty build, using minimal components and could be build with minimal effort.
We could not take a lot of stuff with us to New Zealand.
Camera and powerbanks, those we always take with us. So i only needed:

  • Raspberry Pi
  • Steppermotor and a plastic sheet where it was mounted on (using tiewraps you can undo)
  • Timingbeld
  • Two metal feet it was mounted on

It had to be build strong enough to hold a Nikon 750, and didn’t get out of balance when moving the camera on two metal tubes i bought in NZ.

The RPI would not start anymore, just a red power smd led. SO it didn’t boot.
Taking the mini sdcard out of the raspberry trying to put it in my cardreader .. note the trying part.
The damn thing broke into two parts, never seen anything like it.
Damn, did i backup the latest version? No, i used my mobile and wifi in NZ to modify the scripts.
Well .. “We can rebuild him, we have the technology”

How does it work?

Stepper motors move my camera over two metal rods, with ball bearing wheels.
The raspberry controls my nikon using a usb cable. Mounted on the raspberry is a steppermotor hat (adafruit) which can control DC motors and stepper motors. ( In this project i used only one stepper )
The stepper motor carries the platform containing itself, a raspberry and my nikon over the “rails”
Two switches on each side sends a signal to the program to stop.
All timing are set via the Webgui.

Steps

  • At reboot, python script wil be started
  • Moving platform to the left, until switch detects the edge
  • Waiting for in structions
  • Entering for example timer 30, speed 10 and r
  • Platform wil move distance 10 to the right
  • Wait 30 seconds
  • Grab a picture
  • And loops until end of rod reached, then it wil move to left again.

Notes:

  • Gphoto works with other camera’s also
  • When placing the camera on the platform, focus once. Disable autofocus, also put your camera in manual mode, setting Apeture, ISO and shutterspeed same as your test photo. (bear in mind: when doing sundown shots maybe start with a little light over compensation)

Below old 2018 version

New Sdcard. Format, put lite on this

# install gphoto2
apt-get install photo2
# connect nikon with usb, capture test with
gphoto2 --capture-image-and-download --interval 5
# Next steppers
apt-get install python3-pip
pip3 install adafruit-circuitpython-motorkit
# enable I2C
raspi-config -> enable i2c
reboot

# Test python script
import time
import board
from adafruit_motorkit import MotorKit

kit = MotorKit(i2c=board.I2C())

for i in range(100):
    kit.stepper1.onestep()
    time.sleep(0.01)

# Create a API
apt-get install python3-flask python3-flaskext.wtf

I’m using my phone in Hotspot mode, Timelapser will connect to my phone.
Open a browser and enter : http://<ip of timelapser>:8080/form

timer in seconds to shoot pictures
speed is the movement on the rail
go = r(ight) or l(eft)
go + timer 0, move until you reach the end (switch detect)

Todo: Need to change CSS to mobile responsive gui .. like my quizzer

import time
import subprocess
from flask import Flask, jsonify
from multiprocessing import Process, Value
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField, TextAreaField
from wtforms.validators import DataRequired
from flask import Flask, render_template, request
from flask import render_template
import board
from adafruit_motor import stepper
from adafruit_motorkit import MotorKit
import RPi.GPIO as GPIO
import os; myenv = os.environ.copy(); myenv["LANG"] = "C"


# NOTE: 
# timer = seconds between shots
# speed = distance stepper travel

# Using gpio pins to detect max left/right with switches
# BCM Numbering
GPIO.setmode(GPIO.BCM)
# pullup to 17 &amp; 18
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# Stepper HAT is i2c
kit = MotorKit(i2c=board.I2C())

kit.stepper1.release()

global timer
global speed
timer=0
speed=0
go="nix"

app = Flask(__name__)
app.config['SECRET_KEY'] = 'you-will-never-guess'

class FormForm(FlaskForm):
    timer = StringField('timer', validators=[DataRequired()])
    speed = StringField('speed', validators=[DataRequired()])
    go = StringField('go', validators=[DataRequired()])
    submit = SubmitField('Send control')

# Make below in something like : nikon record .. slowly 10s to the right and recording stop?
# Or bounch left/right using gpio sensors
@app.route("/control/&lt;time&gt;/&lt;speed&gt;")
def action(number, message):
 
    time.sleep(1)

# Print form on: http://&lt;IP&gt;:8080/form = start page 
@app.route("/form")
def form():
    form = FormForm()
    return render_template('web.html', title='Web slide control', form=form)


# process form
@app.route('/data', methods = ['POST', 'GET'])
def data():
    if request.method == 'GET':
        return "The URL /data is accessed directly. Try going to '/form' to submit form"
    if request.method == 'POST':
         
        timer = request.form['timer']
        speed = request.form['speed']
        go = request.form['go']
        timer = int(timer)
        speed = int(speed)
        if timer == 0:
            print("Turn off")
            p = Process(target=record_loop, args=(False,speed,timer,go))
            p.start() 
            if str(go) == "l":
               while GPIO.input(17) == True:
                kit.stepper1.onestep(direction=stepper.FORWARD)
                time.sleep(0.01)
            if str(go) == "r":
               while GPIO.input(18) == True:
                kit.stepper1.onestep(direction=stepper.BACKWARD, style=stepper.DOUBLE)
                time.sleep(0.01)

        else: 
            print("Turn on")
            p = Process(target=record_loop, args=(True,speed,timer,go))
            p.start()  
# print form again
        form = FormForm()
        return render_template('web.html', title='Web slide control', form=form)


# main loop, controls stepper and camera
def record_loop(loop_on,myspeed,mytimer,mygo):
   while True:
      if loop_on == True:
# test if switch hit yet, else move
         print('timer' + str(mytimer))
         print('speed' + str(myspeed))
         time.sleep(2)
         if str(mygo) == "l":
             if GPIO.input(17):
                print("Pin 17 is HIGH")
                for i in range(myspeed):
                        kit.stepper1.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)
                        time.sleep(0.01)
                kit.stepper1.release()
             else:
                print("Pin 17 is LOW")
         if str(mygo) == "r":
             if GPIO.input(18):
                print("Pin 18 is HIGH")
                for i in range(myspeed):
                        kit.stepper1.onestep(direction=stepper.BACKWARD, style=stepper.DOUBLE)
                        time.sleep(0.01)
                kit.stepper1.release()
             else:
                print("Pin 18 is LOW")
         time.sleep(mytimer)
         subprocess.run(['/root/mycapture'])
         subprocess.Popen([
        "gphoto2",
        "--capture-image"],stdout=subprocess.PIPE)

# Main loop
if __name__ == "__main__":
   while GPIO.input(17) == True:
         kit.stepper1.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)
         time.sleep(0.01)
   kit.stepper1.release()
   p = Process(target=record_loop, args=(False,0,0,go))
   p.start()  
   app.run(host='0.0.0.0', port=8080, debug=False)
   p.join()
Other files
cat templates/web.html 
{% block content %}
    <h1>Slide control</h1>
	    <form action="/data" method = "POST">

        {{ form.hidden_tag() }}
        <p>
            {{ form.timer.label }}<br>
            {{ form.timer(size=32) }}
        </p>
        <p>
            {{ form.speed.label }}<br>
            {{ form.speed(size=32) }}
        </p>
        <p>
            {{ form.speed.go }}<br>
            {{ form.go(size=32) }}
        </p>
        <p>{{ form.submit() }}</p>
    </form>
{% endblock %}

gphoto running from cron/python is a b*tch, had to rewrite subprocess and running from screen

Start screen @reboot, just crontab -e
# crontab entry
@reboot screen -dmS slide /usr/bin/python3 /root/control.py
RPI with Stepper Hat and two Limit switches and a stepper motor
Datasheet showing me which colors are what


Table lamp hack

Added: ino file 20220525

Bought a cheap table lamp a few weeks ago.
Runs on batteries and when you flip it over, it turns on or off.

I thought, when i strip this thing of its internals. I can make a wifi/mqtt enabled one.


Opening it up today, i saw a minimalistic print and a battery holder. There was a tilt switch like

Which i wanted to replace by a mercury one i bought in a bunch of sensors a few years ago.

So why go though all the trouble stripping and replacing .. so i didnt

GND and 5v to the batteries, and D4 to the tilt switch. (Measure which side you have to take!) .. I used a pull down of 3k3 ohms

Esp was flashed in the past with Easy ESP .. well lets keep that one for now.

INO version

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Ethernet.h>

const char* ssid = "SSID";
const char* password = "PASSWORD";
const char* mqtt_server = "mqttserver";
const char* mqtt_username = "";
const char* mqtt_password = "";
const char* clientID = "wankel";

const int tiltPin = 4;
int tiltState = 0;    
int previousState = 0;    
WiFiClient espClient;

PubSubClient client(espClient);

void reconnect() {
  while (!client.connected()) {
    if (client.connect(clientID, mqtt_username, mqtt_password)) {
    } else {
      delay(2000);
    }
  }
}

void setup()
{
  {
    client.setServer(mqtt_server, 1883);
    pinMode(tiltPin, INPUT);
  }
}
void loop() {
  tiltState = digitalRead(tiltPin);
  if (tiltState != previousState) {
    if (tiltState == HIGH) {
      client.publish("onoff-wankel/wankel/State", "0"); //
    } else {
      client.publish("onoff-wankel/wankel/State", "1"); //
    }
    delay(100);
  }
  previousState = tiltState;

  {
    if (!client.connected()) {
      reconnect();
    }
    client.loop();
  }
}
Node red + led server

Example is using my ledserver, see other post, but i intent to made a easy to configure node red panel where the to be controlled devices are preconfigured.

[
    {
        "id": "9ec21acaec91aecc",
        "type": "mqtt in",
        "z": "54f3b5b461471f2c",
        "name": "",
        "topic": "onoff-wankel/wankel/State",
        "qos": "2",
        "datatype": "auto",
        "broker": "8c74c5f6.9a7a48",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 400,
        "y": 260,
        "wires": [
            [
                "0fe77b535517f818"
            ]
        ]
    },
    {
        "id": "159f65f444a0d7c2",
        "type": "http request",
        "z": "54f3b5b461471f2c",
        "name": "1 - 30 red",
        "method": "GET",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "http://ledserver:8080/range/01/30/ff0000",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "senderr": false,
        "credentials": {},
        "x": 900,
        "y": 280,
        "wires": [
            []
        ]
    },
    {
        "id": "5806fbfd0e99daab",
        "type": "http request",
        "z": "54f3b5b461471f2c",
        "name": "1 - 30 black",
        "method": "GET",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "http://ledserver:8080/range/01/30/000000",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "senderr": false,
        "credentials": {
            "user": "",
            "password": ""
        },
        "x": 910,
        "y": 220,
        "wires": [
            []
        ]
    },
    {
        "id": "0fe77b535517f818",
        "type": "switch",
        "z": "54f3b5b461471f2c",
        "name": "",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "0",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "1",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 2,
        "x": 660,
        "y": 260,
        "wires": [
            [
                "5806fbfd0e99daab"
            ],
            [
                "159f65f444a0d7c2"
            ]
        ]
    },
    {
        "id": "8c74c5f6.9a7a48",
        "type": "mqtt-broker",
        "name": "mqttserver",
        "broker": "mqttserver",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "compatmode": true,
        "keepalive": "15",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "closeTopic": "",
        "closePayload": "",
        "willTopic": "",
        "willQos": "0",
        "willPayload": ""
    }
]