Tag Archives: hardware

Some Arduino hints/tips/workarounds

These are last weeks findings, I will add to this page when I discover other useful things.

Platformio

  • always include “Arduino.h”
  • Order of functions matter! (Not with Arduino IDE)
  • setup serial monitor speed in platformio.ini
    monitor_speed = 115200

Arduino IDE

  • Build error “panic: runtime error: index out of range [3] with length 3” or length 4.
    Code probably correct, build with another board and build+upload with correct board as workaround.

Generic

  • Using a SSD1306 with other pins?
    For example with Adafruit_SSD1306.h
    in setup(){ place
    Wire.begin(5,4);

Last weeks useful schematics

While working on my game, i had to come up with some solutions i could not find an answer for on the internet.

I’m not going to post every little detail of my game on this blog, my main reason is sharing my experiences and solutions.

16 SWITCHES

16 Switches on a Wemos Arduino. While push buttons are easier to connect, I needed ON/OFF switches.
Push buttons are easy, there is only one active, so 4 enable lines and 4 scan lines and you’re golden.
16 Switches can be enabled all at the same time.
So you need some extra components to get a good result (0-65535)

Above schematic works, you need 4x 1k Pull-up resistors and 16 diodes. I used 1N4007

CONTROLLING 24V using Arduino and a buck convertor

Next problem, i’m using some elevator buttons for a project. These have build-in leds but run at 24V.
I only have 5V from the Arduino.
Regular leds you can connect directly to the Arduino using a 220ohm resistor.
So i used a Buck-Step-Up-Convertor. This little module converts 5V to 24V. (You can control the output voltage using a variable resistor)
To control the lamp/leds i used a PN2222a transistor to switch the lights on/off using a pin of the Arduino.

MT3608 Convertor
  • Input voltage: 2V-24V DC
  • Output voltage: 5V-28V DC
  • Output current: 2A (max), 1A (recommended), <100mA (input <4.0V), <50mA (input <3.5V)

Python Baudot code for Wemos Matrix Led

I wrote a python script to generate binary data to include in my Arduino sketch.
This Arduino displays codes send though MQTT.

https://en.wikipedia.org/wiki/Baudot_code

CODE:

python3 matrix.py apple gives me

byte apple_Char[8] = {
  0b00000000,
  0b01000100,
  0b01111000,
  0b00000000,
  0b00110000,
  0b00000000,
  0b00111000,
  0b00000000
};

Python Code
import sys

a = [ 
        [0,0,0,0,0,0,0,0 ], 
        [0,0,0,0,0,0,0,0 ], 
        [0,0,0,0,0,0,0,0 ], 
        [0,0,0,0,0,0,0,0 ], 
        [0,0,0,0,0,0,0,0 ], 
        [0,0,0,0,0,0,0,0 ], 
        [0,0,0,0,0,0,0,0 ], 
        [0,0,0,0,0,0,0,0 ] 
    ] 

letters = [
        [0,1,1,0,0,0,0,0 ],
        [0,1,0,0,0,1,1,0 ],
        [0,0,1,0,1,1,0,0 ],
        [0,1,0,0,0,1,0,0 ],
        [0,1,0,0,0,0,0,0 ],
        [0,1,0,0,1,1,0,0 ],
        [0,0,1,0,0,1,1,0 ],
        [0,0,0,0,1,0,1,0 ],
        [0,0,1,0,1,0,0,0 ],
        [0,1,1,0,0,1,0,0 ],
        [0,1,1,0,1,1,0,0 ],
        [0,0,1,0,0,0,1,0 ],
        [0,0,0,0,1,1,1,0 ],
        [0,0,0,0,1,1,0,0 ],
        [0,0,0,0,0,1,1,0 ],
        [0,0,1,0,1,0,1,0 ],
        [0,1,1,0,1,0,1,0 ],
        [0,0,1,0,0,1,0,0 ],
        [0,1,0,0,1,0,0,0 ],
        [0,0,0,0,0,0,1,0 ],
        [0,1,1,0,1,0,0,0 ],
        [0,0,1,0,1,1,1,0 ],
        [0,1,1,0,0,0,1,0 ],
        [0,1,0,0,1,1,1,0 ],
        [0,1,0,0,1,0,1,0 ],
        [0,1,0,0,0,0,1,0 ]
        ]

number=0
word=str(sys.argv[1])

for col in range(len(word)) :
    character=word[col]

    number = ord(character) - 97
    nextcol = col + 1
    for row in range(len(a[col])) :
        a[row][nextcol] = letters[number][row]


print("byte " + word + "_Char[8] = {")
for i in range(len(a)) : 
    print("  0b", end = '')
    for j in range(len(a[i])) : 
        print(a[i][j], end="")   
    if i < 7:
        print(",")
print()
print("};")

Arduino test code

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiClient.h>


#include "WEMOS_Matrix_LED.h"
MLED mled(5); //set intensity=5

const char* wifi_ssid = "MYSSID"; // Enter your WiFi name
const char* wifi_password =  "MYSSIDPASS"; // Enter WiFi password
const char* mqtt_server = "MYMQTTSERVER";
const int mqtt_port = 1883;
const char* mqttUser = "";
const char* mqttPassword = "";
#define MSG_BUFFER_SIZE  (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;

WiFiClient espClient;

PubSubClient mqtt(espClient);

void setup_wifi() {
  delay(10);
  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid, wifi_password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
}
 
byte clear_Char[8] = {  
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000
};
 
byte baudot_Char[8] = {
  0b11111111,
  0b01101010,
  0b00011100,
  0b11111111,
  0b00110100,
  0b00010000,
  0b00000100,
  0b11111111  
};
 

 
#define TIME 500
 
void setup() { 
    Serial.begin(115200);
      setup_wifi();
        mqtt.setServer(mqtt_server, mqtt_port);

WiFiClient espClient;
PubSubClient mqtt(espClient);

  mqtt.setClient(espClient);
  mqtt.setServer(mqtt_server, mqtt_port);
      delay(500);

  mqtt.subscribe("escape/matrixledin");
        delay(500);

  mqtt.setCallback(callback);

  }

void callback(char* topic, byte* payload, unsigned int length) {
        Serial.println("callback");
    String topicStr = topic;
      byte value = atoi((char*)payload);
        snprintf (msg, MSG_BUFFER_SIZE, "%1d", value);

              mqtt.publish("escape/matrixledout", msg);
       if (value == 1){

drawChar(baudot_Char); 

 }else if (value == 0){
  drawChar(cleat_Char); 
  }else if (value == 2){
  drawChar(test_Char); 
  }else if (value == 3){
  drawChar(no_Char); 
 }
 }

void reconnect() {

  while (!mqtt.connected()) {
    String clientId = "matrixClient-";
    clientId += String(random(0xffff), HEX);
    if (mqtt.connect(clientId.c_str())) {
      mqtt.publish("escape/outTopic", "hello from 8x8led module");
                Serial.println("resubscribe");

      mqtt.subscribe("escape/matrixledin");
        mqtt.setCallback(callback);

    } else {
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}
 
void loop() {

 if (!mqtt.connected()) {
          Serial.println("reconnect called");
    reconnect();
  }
    mqtt.loop();

}
 
void drawChar(byte character[8]) {
  for(int y=7;y>=0;y--) {
  for (int x=0; x <= 7; x++) { 
    if (character[(7-y)] & (B10000000 >> x)) {
     mled.dot(x,y); // draw dot
    } else {
     mled.dot(x,y,0);//clear dot
    }
  }
  mled.display();  
  }
}

Playing with lasercutter steppermotors

Busy day: I’ve airbrushed some 3D pieces a few days ago, but i need 50 or so more.
Meanwhile is was reinstalling octoprint, and making a new version of my Bluetooth page flipper. (Android Music Sheet Pedal Thingy. Which i also didn’t post apparently)
But the main project was this:

I was curious how fast the stepper motors are on my laser cutter. And for what can we utilize this!

So I took a Raspberry Zero and some rotary encoders, lets make an etch-a-sketch like thingy.


Some rotary encoder modules I had.

Next to do: 3D print a pen holder, and alter the code to enable the laser when moving!

CODE

Below code uses a simple rotary class, and generates control GCodes for the steppers/Sculpfun

import time
import serial
import RPi.GPIO as GPIO
from encoder import Encoder

def valueChanged(value, direction):
    print("* New value: {}, Direction: {}".format(value, direction))

GPIO.setmode(GPIO.BCM)

e1 = Encoder(20, 21, valueChanged)
e2 = Encoder(16, 12, valueChanged)

x = 0
y = 0
arduino = serial.Serial('/dev/ttyUSB0', 115200, timeout=.1)

newx = 0
mystringx = ""
newy = 0
mystringy = ""

arduino.write(str.encode("G00 G17 G40 G21 G54\r\n"))
arduino.write(str.encode('G90\r\n'))
arduino.write(str.encode('M4\r\n'))
arduino.write(str.encode('M8\r\n'))
arduino.write(str.encode('G0 X41.5Y36.05\r\n'))
arduino.write(str.encode('M3\r\n'))
#arduino.write(str.encode('G91\r\n'))
arduino.write(str.encode('G1 X2.5F6000S0\r\n'))
arduino.write(str.encode('G1 X0\r\n'))
arduino.write(str.encode('G1 Y0\r\n'))

try:
    while True:
        data = arduino.readline()[:-2] #the last bit gets rid of the new-line chars
        if data:
                print (data)
        arduino.write(str.encode("G1 F10000\r\n"))
        newx=e1.getValue() *5 + 100
        newy=e2.getValue() *5 + 100
        mystringx=f"G1 X{newx}\r\n"
        mystringy=f"G1 Y{newy}\r\n"
#        print(mystringx)
        arduino.write(str.encode(mystringx))
        arduino.write(str.encode(mystringy))

except Exception:
    pass

GPIO.cleanup()

LCD Display with rotary encoder on Wemos using MQTT and Node-red

  • Sends a “connected” to Mosquitto
  • Mqtt controls Display
  • Rotary values are displayed, a push on the rotary sends the value to Mosquitto
Schematic : capacitors are 100nF and display has an I2C backpack
Node-red flow example
Node red GUI

Code :

Notes: There is a problem with 4 line LCD using LiquidCrystal_I2C
Lines 3 and 4 will be shifted 4 characters to the right.
Workaround is: lcd.setCursor(-4, 2); // Go to column 0, row 3

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiClient.h>
#include "SoftwareSerial.h"
#include <Ethernet.h>
#include <Arduino.h>
#include <RotaryEncoder.h>
#define wifi_ssid "MYSSID"
#define wifi_password "MYSSIDPASS"
#define mqtt_server "MQTTSERVER"
#define mqtt_port 1883

WiFiClient espClient;
EthernetClient ethClient;

PubSubClient mqtt(espClient);

#include <Wire.h>                  // Include Wire library (required for I2C devices)
#include <LiquidCrystal_I2C.h>     // Include LiquidCrystal_I2C library 
 
LiquidCrystal_I2C lcd(0x27, 16, 4);  // Configure LiquidCrystal_I2C library with 0x27 address, 16 columns and 4 rows
volatile bool flag = false;


#define PIN_IN1 D7
#define PIN_IN2 D6
#define push D5
int temp = 0;

RotaryEncoder *encoder = nullptr;

#if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_NANO_EVERY)
// This interrupt routine will be called on any change of one of the input signals
void checkPosition()
{
  encoder->tick(); // just call tick() to check the state.
}

#elif defined(ESP8266)
/**
 * @brief The interrupt service routine will be called on any change of one of the input signals.
 */
IRAM_ATTR void checkPosition()
{
  encoder->tick(); // just call tick() to check the state.
}

#endif

void scrollText(int row, String message, int delayTime, int lcdColumns) {
  for (int i=0; i < lcdColumns; i++) {
    message = " " + message;  
  } 
  message = message + " "; 
  for (int pos = 0; pos < message.length(); pos++) {
    lcd.setCursor(0, row);
    lcd.print(message.substring(pos, pos + lcdColumns));
    delay(delayTime);
  }
}

void setup_wifi() {
  delay(10);
  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid, wifi_password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
}
 
void setup() {
    setup_wifi();
  mqtt.setServer(mqtt_server, mqtt_port);
  mqtt.setCallback(callback);
  Serial.begin(115200);
  Serial.println("initializing...");

  WiFiClient espClient;
PubSubClient mqtt(espClient);

 mqtt.setClient(espClient);
  mqtt.setServer(mqtt_server, 1883);
    
mqtt.setCallback(callback);
   mqtt.subscribe("escape/display1/#");

  lcd.init();                        // Initialize I2C LCD module
  lcd.backlight();                   // Turn backlight ON
 
  lcd.setCursor(0, 0);               // Go to column 0, row 0
  lcd.print("Init");
  lcd.setCursor(0, 1);               // Go to column 0, row 1
  lcd.print("Display #1");

  encoder = new RotaryEncoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);

  // register interrupt routine
  attachInterrupt(digitalPinToInterrupt(PIN_IN1), checkPosition, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_IN2), checkPosition, CHANGE);

 pinMode(push, INPUT_PULLUP);
}

void reconnect() {
  // Loop until we're reconnected
  while (!mqtt.connected()) {
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (mqtt.connect(clientId.c_str())) {
      // Once connected, publish an announcement...
      mqtt.publish("escape", "display1 connected");
      // ... and resubscribe
      mqtt.subscribe("escape/display1/#");
    } else {
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void callback(char* topic, byte* payload, unsigned int length) {

payload[length]= '\0';
char * charPointer = (char *)payload;
String s="";
s =charPointer;
s = s + "               "; 
    String topicStr = topic;

if (topicStr == "escape/display1/clear"){
   lcd.clear();
}
if (topicStr == "escape/display1/1in"){
  lcd.setCursor(0, 0);               // Go to column 0, row 1
  lcd.print(s.substring(0, 16));
}
if (topicStr == "escape/display1/2in"){
  lcd.setCursor(0, 1);               // Go to column 0, row 2
  lcd.print(s.substring(0, 16));
}
if (topicStr == "escape/display1/3in"){
  lcd.setCursor(-4, 2);               // Go to column 0, row 3
  lcd.print(s.substring(0, 16));
}
if (topicStr == "escape/display1/4in"){
  lcd.setCursor(-4, 3);               // Go to column 0, row 4
  lcd.print(s.substring(0, 16));
}
    }
 
void loop() {
   if (!mqtt.connected()) {
    reconnect();
  }
    mqtt.loop();

  static int pos = 0;

  encoder->tick(); // just call tick() to check the state.

  int newPos = encoder->getPosition() / 2;
    if (pos != newPos) {
    String nr="";
    Serial.print("pos:");
    Serial.print(newPos);
    Serial.print(" dir:");
    Serial.println((int)(encoder->getDirection()));
    pos = newPos;
 // hier nog iets mee doen 
   // zonder setPos moet je eerst lang clockwise voordat weer gaat tellen
    // met setPos blijft 0
   // if (pos < 0){
    //  pos = 0;
   //     encoder->setPosition(0);
   // }
    
    nr = pos + "        ";
    lcd.setCursor(10, 3);               // Go to column 10, row 3
  lcd.print(pos);
  lcd.print("   ");
  }

  temp = digitalRead(push);
  if (temp == LOW) {
    
char msg_out[20];
sprintf(msg_out, "%d",pos);
        mqtt.publish("escape/display1/rotary", msg_out);
  }

}

Mini DF MP3 player with MQTT control

Resistor is 1K, speaker is 4 ohm

I’ve got the DFPlayer with the GD3200B instead of the better YX5200, but it works.

As part of my game, so MQTT controlled.

First sound is low in volume.

Code

I’m using Soft Serial

// based on code from: 
// https://github.com/Makuna/DFMiniMp3/blob/master/examples/PlayMp3/PlayMp3.ino
// above example has no wifi/mqtt and is missing the SoftSerial include line
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiClient.h>
#include <DFMiniMp3.h>
#include "SoftwareSerial.h"
#include <Ethernet.h>

#define wifi_ssid "SSID"
#define wifi_password "SSIDPASS"
#define mqtt_server "MQTTSERVER"
#define mqtt_port 1883

WiFiClient espClient;
EthernetClient ethClient;
PubSubClient mqtt(espClient);

class Mp3Notify; 

SoftwareSerial secondarySerial(D6, D5); // RX, TX
typedef DFMiniMp3<SoftwareSerial, Mp3Notify> DfMp3;
DfMp3 dfmp3(secondarySerial);

class Mp3Notify
{
public:
  static void PrintlnSourceAction(DfMp3_PlaySources source, const char* action)
  {
    if (source & DfMp3_PlaySources_Sd) 
    {
        Serial.print("SD Card, ");
    }
    if (source & DfMp3_PlaySources_Usb) 
    {
        Serial.print("USB Disk, ");
    }
    if (source & DfMp3_PlaySources_Flash) 
    {
        Serial.print("Flash, ");
    }
    Serial.println(action);
  }
  static void OnError([[maybe_unused]] DfMp3& mp3, uint16_t errorCode)
  {
    // see DfMp3_Error for code meaning
    Serial.println();
    Serial.print("Com Error ");
    Serial.println(errorCode);
  }
  static void OnPlayFinished([[maybe_unused]] DfMp3& mp3, [[maybe_unused]] DfMp3_PlaySources source, uint16_t track)
  {
    Serial.print("Play finished for #");
    Serial.println(track);  

    // start next track
    track += 1;
    // this example will just start back over with 1 after track 3
    if (track > 3) 
    {
      track = 1;
    }
    dfmp3.playMp3FolderTrack(track);  // sd:/mp3/0001.mp3, sd:/mp3/0002.mp3, sd:/mp3/0003.mp3
  }
  static void OnPlaySourceOnline([[maybe_unused]] DfMp3& mp3, DfMp3_PlaySources source)
  {
    PrintlnSourceAction(source, "online");
  }
  static void OnPlaySourceInserted([[maybe_unused]] DfMp3& mp3, DfMp3_PlaySources source)
  {
    PrintlnSourceAction(source, "inserted");
  }
  static void OnPlaySourceRemoved([[maybe_unused]] DfMp3& mp3, DfMp3_PlaySources source)
  {
    PrintlnSourceAction(source, "removed");
  }
};

void setup_wifi() {
  delay(10);
  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid, wifi_password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
}

void setup() 
{
  setup_wifi();
  mqtt.setServer(mqtt_server, mqtt_port);
  mqtt.setCallback(callback);
  Serial.begin(115200);
  Serial.println("initializing...");

  WiFiClient espClient;
  PubSubClient mqtt(espClient);

  mqtt.setClient(espClient);
  mqtt.setServer(mqtt_server, 1883);
    
  mqtt.setCallback(callback);
  mqtt.subscribe("escape/soundin");
  
  dfmp3.begin();

  uint16_t volume = dfmp3.getVolume();
  Serial.print("volume ");
  Serial.println(volume);
  dfmp3.setVolume(24);
  
  uint16_t count = dfmp3.getTotalTrackCount(DfMp3_PlaySource_Sd);
  Serial.print("files ");
  Serial.println(count);
  
  Serial.println("starting...");

  // start the first track playing
  // dfmp3.playMp3FolderTrack(1);  // sd:/mp3/0001.mp3
}

void reconnect() {
  // Loop until we're reconnected
  while (!mqtt.connected()) {
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (mqtt.connect(clientId.c_str())) {
      // Once connected, publish an announcement...
      mqtt.publish("escape", "sound connected");
      // ... and resubscribe
      mqtt.subscribe("escape/soundin");
    } else {
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}


void callback(char* topic, byte* payload, unsigned int length) {
    //  digitalWrite(led, HIGH);

    String topicStr = topic;
      byte value = atoi((char*)payload);
dfmp3.playMp3FolderTrack(value);  // sd:/mp3/0001.mp3
  Serial.println(value);
}

void waitMilliseconds(uint16_t msWait)
{
  uint32_t start = millis();

  while ((millis() - start) < msWait)
  {
    dfmp3.loop(); 
    delay(1);
  }
}

void loop() 
{
  
  if (!mqtt.connected()) {
    reconnect();
  }
    mqtt.loop();
  waitMilliseconds(100);
}

Wemos with Keypad, led and 7 segment display using MQTT

Warning, read the notes!

There are several caveats.

  • I was needing ALL GPIO pins, even RX/TX ( see trick below)
    When doing so, you can’t use serialprint.
    Do NOT enable, your sketch won’t work!
  • Don’t use pullup on D8, you can’t upload to the wemos if you do that
  • Due to library conflicts in keypad.h, DON’T change the order in the source. You will end up with compile errors!
  • The keypad has a weird pinout, but there are similar keypads with alternative layouts. Measure this using a multimeter.
  • The pull-up resistors will help fighting ghost key presses!
  • I2C needs D1/D2

To use RX/TX as GPIO pins you need to do the following:

//Define pins
  int led = 1; //tx
  int col = 3; //rx

// Change to function mode 3
// see https://www.esp8266.com/wiki/doku.php?id=esp8266_gpio_pin_allocations
  pinMode(1, FUNCTION_3);
  pinMode(3, FUNCTION_3);
 
// Revert to normal mode
// pinMode(1, FUNCTION0);

// Define mode input/output
// i'm using led to control the led so thats an output
// I'm using col for the keypad column scanner, that's an input
  pinMode(led, OUTPUT);
  pinMode(col, INPUT);

Complete code

The (*) clears input
The (#) sends the pin code using MQTT

Sending a 0 or 1 to escape/keypadin topic will toggle the led

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiClient.h>
// Do not change order!
#include "Keypad.h"
#include <TM1637Display.h>
#include <Ethernet.h>

#define wifi_ssid "SSID"
#define wifi_password "SSIDPASS"
#define mqtt_server "MQTTSERVER"
#define mqtt_port 1883

#define MSG_BUFFER_SIZE  (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;

const byte ROWS = 4; //four rows
const byte COLS = 3; //four columns

int led = 1; //tx
int col = 3; //rx

#define CLK D1
#define DIO D2
#define TEST_DELAY   2000
TM1637Display display(CLK, DIO);

char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte rowPins[ROWS] = {D3, D5 , D6 , D7 };
byte colPins[COLS] = {D4 , col, D8 };

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
int keyNum = 0;
WiFiClient espClient;
EthernetClient ethClient;

PubSubClient mqtt(espClient);

void setup_wifi() {
  delay(10);
  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid, wifi_password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
}


void setup() {
  setup_wifi();
  mqtt.setServer(mqtt_server, mqtt_port);
  mqtt.setCallback(callback);
  
  pinMode(1, FUNCTION_3);
  pinMode(3, FUNCTION_3);
  pinMode(led, OUTPUT);
  pinMode(col, INPUT);
  // using above? .. then disable serial!
  // Serial.begin(9600);
display.showNumberDec(0, true);
delay(TEST_DELAY);
WiFiClient espClient;
PubSubClient mqtt(espClient);

 mqtt.setClient(espClient);
 mqtt.setServer(mqtt_server, 1883);
    
mqtt.setCallback(callback);
mqtt.subscribe("escape/keypadin");

}

void callback(char* topic, byte* payload, unsigned int length) {
    //  digitalWrite(led, HIGH);

    String topicStr = topic;
      byte value = atoi((char*)payload);
       if (value == 1){
    digitalWrite(led, HIGH);

 }else if (value == 0){
    digitalWrite(led, LOW);
 }
    

}

void reconnect() {
  while (!mqtt.connected()) {
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    if (mqtt.connect(clientId.c_str())) {
      mqtt.publish("outTopic", "hello world");
      mqtt.subscribe("escape/keypadin");
    } else {
      delay(5000);
    }
  }
}



void loop() {

  if (!mqtt.connected()) {
    reconnect();
  }
    mqtt.loop();

  // put your main code here, to run repeatedly:
  char key = keypad.getKey();

  if (key) {

    if(key=='*'){
      keyNum = 0;
    } else if (key=='#'){
         ++value;
  snprintf (msg, MSG_BUFFER_SIZE, "#%1d", keyNum);
        mqtt.publish("escape/keypad", msg);
    }
    
       else{
      if(keyNum<=999){
        keyNum = (keyNum*10) + (int(key)-48);
      }
    }
    
    //  Serial.println(key);
    display.setBrightness(0x0f);

    uint8_t data[] = { 0x0, 0x0, 0x0, 0x0 };
    display.setSegments(data);

    display.setSegments(data);
    display.showNumberDec(keyNum);

  }

}

Shelly Devices

I love shellies, easy to implement and hacker friendly.

MQTT out of the box.
Curl in and out – you can switch it on/off using curl, but it can send a http command also.
I’ve used this with Domoticz and Home Assistant.
It has a webinterface, with timers, and there is also a client for Android/Iphone
You’ve got some own gpio pins to your disposal and the unit is flash-able!

curl -X POST https://shellydevice/device/relay/control -d "channel=IDHERE&turn=on&id=ID&auth_key=AUTH"

The device is not isolated from the mains. To flash it, the mains must be disconnected.

SHELLY 1

I use this for simple on/off switches around the house.
Using it with a physical switch and MQTT (Nodered)

SHELLY 2 PM

Same as above but this one has a build in power meter

SHELLY DIMMER

Generic dimmer

Dimmer with low voltage rotary encoder!
https://www.instructables.com/Shelly-Dimmer-Wall-Switch-With-Rotary-Knob-and-Hom/

SHELLY RGBW2

A RGBW / 4 Channel controller
You can connect RGB strips, but also dimmable white strips in 4 channels. 12V or 24V.
NOTE! : There is a common 12V connection, and GND will be controlled!

SHELLY PLUG S

I love these small wall plugs, i’ve used these also to find power consuming devices around the house.

For example, i made a nodered flow, to see if the washing machines are running or not.

SHELLY BUTTON

This became my all purpose alarm thinghy

SHELLY DOORSENSOR

A door sensor WITH temperature and light sensor build in!

Home Assistant example

SHELLY WATER SENSOR

This one lays below our washing machine

SHELLY SMOKE ALARM

(Preordered)

SHELLY PM4

A four channel power measure/switch for your fuse box


GENERIC SHELLY STUFF
A smart doorbell schematic i found

https://www.thingiverse.com/thing:5756154
Very nice .. printable cases for your shellies!

Mobile Raspberry Access Point with Mqtt and a display

UPDATE: 20230214 / 20230224

Install Bullseye on a SDCard

Enable wifi country code using raspi-conf
(While you at it, enable I2C for the display)

Install and configure an Access Point

# As root
apt update
apt upgrade
apt install hostapd
apt install dnsmasq
systemctl stop hostapd
systemctl stop dnsmasq

cat <<EOF > /etc/hostapd/hostapd.conf
interface=wlan0
driver=nl80211
ssid=escape
hw_mode=g
channel=6
wmm_enabled=0
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=mysecretpass
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
EOF

cat <<EOF >> /etc/dnsmasq.conf
interface=wlan0
bind-dynamic
domain-needed
bogus-priv
dhcp-range=192.168.50.150,192.168.50.200,255.255.255.0,12h
EOF

cat <<EOF >> /etc/dhcpcd.conf
interface wlan0
nohook wpa_supplicant
static ip_address=192.168.50.10/24
static routers=192.168.50.1
static domain_name_servers=8.8.8.8
EOF

sed -i s/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g /etc/sysctl.conf


mkdir /etc/nftables
cat <<EOF > /etc/nftables/nft-stat-ap.nft
flush ruleset

table inet ap {
        chain routethrough {
                type nat hook postrouting priority filter; policy accept;
                oifname "eth0" masquerade
        }

        chain fward {
                type filter hook forward priority filter; policy accept;
                iifname "eth0" oifname "wlan0" ct state established,related accept
                iifname "wlan0" oifname "eth0" accept
        }
}
EOF

chmod +x /etc/nftables/nft-stat-ap.nft
cat /etc/nftables.conf | grep nft-stat-ap.nft || echo 'include "/etc/nftables/nft-stat-ap.nft"' >> /etc/nftables.conf

systemctl unmask hostapd
systemctl enable hostapd
systemctl enable nftables

reboot

UPDATE: 20230214

Now in its case, added two buttons and one led.

UPDATE : 20230224 mqtt config

apt-get install mosquitto mosquitto-clients

vi /etc/mosquitto/conf.d/remotemqtt.conf
per_listener_settings true
# internal mqtt
listener 1883
allow_anonymous true
# connection over the internet
connection bridge-01
address remoteserver:8883
bridge_cafile /etc/mosquitto/certs/ca.crt
bridge_keyfile /etc/mosquitto/certs/remoteaccesspoint.key
bridge_certfile /etc/mosquitto/certs/remoteaccesspoint.crt
topic escape/# both 0
remote_username remoteuser
remote_password remotepass

########## remote server config

cd /etc/mosquitto
mosquitto_passwd passwords remoteuser

cd /etc/mosquitto/certs
./generate-CA.sh client remoteaccesspoint

copy ca.crt remoteaccesspoint.key and remoteaccesspoint.crt to accesspoint

mosquitto.conf
pid_file /var/run/mosquitto.pid
persistence true
persistence_location /var/lib/mosquitto/
#per_listener_settings true
# Plain MQTT protocol
listener 1883
allow_anonymous true
# End of plain MQTT configuration
# MQTT over TLS/SSL
listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/webserver.fash.lab.crt
keyfile /etc/mosquitto/certs/webserver.fash.lab.key
allow_anonymous false
password_file /etc/mosquitto/passwords
# End of MQTT over TLS/SLL configuration
listener 9001
protocol websockets
# End of plain Websockets configuration
# WebSockets over TLS/SSL
listener 9883
protocol websockets
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/webserver.fash.lab.crt
keyfile /etc/mosquitto/certs/webserver.fash.lab.key
log_dest file /var/log/mosquitto/mosquitto.log
include_dir /etc/mosquitto/conf.d
connection bridge-01
address extramqttserver:1883
topic lscspm1/# both 0
topic owntracks/# both 0
topic escape/# both 0

log_type all


Controlling Display and MQTT messages examples

apt-get install python3-smbus

python3 printline.py -1 "line 1" -2 "line 2"

wget https://github.com/emcniece/rpi-lcd/blob/master/RPi_I2C_driver.py

cat printline.py
# requires RPi_I2C_driver.py
import RPi_I2C_driver
from time import *
import sys, getopt

#python3 fix
unichr = chr 

mylcd = RPi_I2C_driver.lcd()
# test 2                  1234567812345678


def main(argv):
   line1 = ''
   line2 = ''
   try:
      opts, args = getopt.getopt(argv,"h1:2:",["txt1=","txt2="])
   except getopt.GetoptError:
      print ('printline.py -1 <line1> -2 <line2>')
      sys.exit(2)
   for opt, arg in opts:
      if opt == '-h':
         print ('printline.py -1 <line1> -2 <line2>')
         sys.exit()
      elif opt in ("-1", "--txt1"):
         line1 = arg
      elif opt in ("-2", "--txt2"):
         line2 = arg

   mylcd.lcd_display_string(line1, 1)
   mylcd.lcd_display_string(line2, 2)
if __name__ == "__main__":
   main(sys.argv[1:])

Print internal and external ip

myip=$(/usr/sbin/ifconfig eth0 | grep "inet " | awk '{ print $2 }')
extip=$(curl -s http://whatismyip.akamai.com/)
python3 printline.py -1 "i $myip" -2 "e $extip"

mosquitto health tester

timeout 1 mosquitto_sub -t '$SYS/#' -C 1 | grep -v Error || exit 1

Button press shutdown

raspi-gpio get 27  | grep level=0 >/dev/null 
if [ $? == 0 ] ; then

python3 printline.py -1 "shutting" -2 "down"
/usr/sbin/halt -p
fi

Cleaned-up minimal mqtt poster

#include <WiFi.h>
#include <PubSubClient.h>

const char* ssid = "ssidname";
const char* password = "ssidpass";
const char* mqttServer = "192.168.50.10";

WiFiClient espClient;
PubSubClient client(espClient);


void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}


void setup() {
Serial.begin(115200);
initWiFi();
  Serial.print("RRSI: ");
  Serial.println(WiFi.RSSI());
    client.setClient(espClient);
    client.setServer(mqttServer,1883);
 if (client.connect("testmodule")) {

      Serial.println("connected");
 client.publish("escape/testclient", "connected");
    } else {
            Serial.println("Mqtt not connected");
    }

}

void loop() {
        }

}

ARDUINO CONCERTINA – POC 2

See also

Potmeter needs some tweaking

New code

#include <Keypad.h>
int buzzer=9;
int lastsensorread;
int prevkey;
int push=450;
int pull=550;

const byte ROWS = 8; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'#','0','*'},
  {'A','B','C'},
  {'D','E','F'},
  {'G','H','I'},
  {'J','K','L'}
};
byte rowPins[ROWS] = {5, 6, 7, 8, 10, 11, 12, 13}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {2, 3, 4 }; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup(){
  Serial.begin(9600);
  pinMode(buzzer,OUTPUT);

}
  
void loop(){
  char key = keypad.getKey();
//  if (key == NO_KEY){
 //   key = prevkey;
   //   }
      
  
 // if (key != NO_KEY){
    int freq = 0;
    int sensorValue = analogRead(A0);
    //sensorValue = ((sensorValue+4)/5)*5;



    
    if (sensorValue > push && sensorValue < pull   ) {
    // Serial.println("No pull or push");
    noTone(buzzer);
    }
    else if (key == NO_KEY){
      switch (keypad.getState()){
            case RELEASED:
             noTone(buzzer);
      }
    }
    else 
    {
    if (key == '1' && sensorValue < push ) { tone(buzzer,415); }; // G push
    if (key == '1' && sensorValue > pull ) { tone(buzzer,466); }; // A pull
    if (key == '2' && sensorValue < push ) { tone(buzzer,392); }; // G push
    if (key == '2' && sensorValue > pull ) { tone(buzzer,440); }; // A pull
    if (key == '3' && sensorValue < push ) { tone(buzzer,587); }; // G push
    if (key == '3' && sensorValue > pull ) { tone(buzzer,659); }; // A pull
    
    if (key == '4' && sensorValue < push ) { tone(buzzer,440); };
    if (key == '4' && sensorValue > pull ) { tone(buzzer,392); };
    if (key == '5' && sensorValue < push ) { tone(buzzer,329); };
    if (key == '5' && sensorValue > pull ) { tone(buzzer,349); };
    if (key == '6' && sensorValue < push ) { tone(buzzer,493); };
    if (key == '6' && sensorValue > pull ) { tone(buzzer,523); };
      //8l f/e
    if (key == '8' && sensorValue < push ) { tone(buzzer,261); };
    if (key == '8' && sensorValue > pull ) { tone(buzzer,587); };

    if (key == 'A' && sensorValue < push ) { tone(buzzer,783); };
    if (key == 'A' && sensorValue > pull ) { tone(buzzer,739); };
    if (key == 'B' && sensorValue < push ) { tone(buzzer,523); };
    if (key == 'B' && sensorValue > pull ) { tone(buzzer,493); };

    if (key == 'D' && sensorValue < push ) { tone(buzzer,987); };
    if (key == 'D' && sensorValue > pull ) { tone(buzzer,880); };
    if (key == 'E' && sensorValue < push ) { tone(buzzer,659); };
    if (key == 'E' && sensorValue > pull ) { tone(buzzer,587); };

    if (key == 'H' && sensorValue < push ) { tone(buzzer,783); };
    if (key == 'H' && sensorValue > pull ) { tone(buzzer,698); };
    //tone(buzzer,freq);
    }
    Serial.println(sensorValue);
    Serial.println(key);
    Serial.println(freq);
 //   lastsensorread = sensorValue;
    prevkey = key;
      
 // }
}