Tag Archives: arduino

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();  
  }
}

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

  }

}

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;
      
 // }
}

Arduino Concertina – POC

As mentioned in post below

Update: https://www.henriaanstoot.nl/2023/01/17/arduino-concertina-poc-2/

So i’ve bought some needed parts and made a proof of concept.

First to try : 3×4 matrix .. later the full 30 keys version
First part Bella Ciao

Arduino Code
Needs https://playground.arduino.cc/Code/Keypad/ keypad library
Not all buttons are configured with frequencies … yet

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

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 == '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); };
    
    //tone(buzzer,freq);
    }
    Serial.println(sensorValue);
    Serial.println(key);
    Serial.println(freq);
 //   lastsensorread = sensorValue;
    prevkey = key;
      
 // }
}

Lets make a test holder from pieces of wood, when i’ve got the sizes correct, i’ll 3D print something

Servo’s Rotary encoders, Node-red and Mqtt

Multiple rotary encoders are controlling a servo based lock. 3 players have to work together to open the lock.

Secure MQTT rotary encoder (Can be used over the internet)
Servo based lock
Lock Mockup
Node red test logic

Arduino Rotary button (mqtt)

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <time.h>
#include <PubSubClient.h>

#define encoderCLK 5   //D1
#define encoderDT 4    //D2
int servoAngle = 0;
int crntCLK;
int prvsCLK;
String myString;
char ang[50];

#ifndef SECRET
const char ssid[] = "MYSSID";
const char pass[] = "MSSIDPASS";

#define HOSTNAME "rotary1"

const char MQTT_HOST[] = "securemqttserver";
const int MQTT_PORT = 8883;
const char MQTT_USER[] = "user"; // leave blank if no credentials used
const char MQTT_PASS[] = "pass"; // leave blank if no credentials used

const char MQTT_SUB_TOPIC[] = "escape/" HOSTNAME "/in";
const char MQTT_PUB_TOPIC[] = "escape/" HOSTNAME "/out";
const char MQTT_PUB_TOPIC_angle[] = "escape/" HOSTNAME "/angle";

#ifdef CHECK_CA_ROOT
static const char digicert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIFtTCCA52gAwIBAgIUXEEQRLHhYox8a95YiAYX/wQ/XeMwDQYJKoZIhvcNAQEN
----8< snip snap
CyLjTT2rtllw==
-----END CERTIFICATE-----
)EOF";
    #endif

    #ifdef CHECK_PUB_KEY
    // Extracted by: openssl x509 -pubkey -noout -in ca.crt
    static const char pubkey[] PROGMEM = R"KEY(
    -----BEGIN PUBLIC KEY-----
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxx
    -----END PUBLIC KEY-----
    )KEY";
    #endif

    #ifdef CHECK_FINGERPRINT
	// Extracted by: openssl x509 -fingerprint -in ca.crt
    static const char fp[] PROGMEM = "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD";
    #endif
#endif

//////////////////////////////////////////////////////

#if (defined(CHECK_PUB_KEY) and defined(CHECK_CA_ROOT)) or (defined(CHECK_PUB_KEY) and defined(CHECK_FINGERPRINT)) or (defined(CHECK_FINGERPRINT) and defined(CHECK_CA_ROOT)) or (defined(CHECK_PUB_KEY) and defined(CHECK_CA_ROOT) and defined(CHECK_FINGERPRINT))
  #error "cant have both CHECK_CA_ROOT and CHECK_PUB_KEY enabled"
#endif

BearSSL::WiFiClientSecure net;
PubSubClient client(net);

time_t now;
unsigned long lastMillis = 0;

void mqtt_connect()
{
  while (!client.connected()) {
    Serial.print("Time: ");
    Serial.print(ctime(&now));
    Serial.print("MQTT connecting ... ");
    if (client.connect(HOSTNAME, MQTT_USER, MQTT_PASS)) {
      Serial.println("connected.");
      client.subscribe(MQTT_SUB_TOPIC);
    } else {
      Serial.print("failed, status code =");
      Serial.print(client.state());
      Serial.println(". Try again in 5 seconds.");
      /* Wait 5 seconds before retrying */
      delay(5000);
    }
  }
}

void receivedCallback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Received [");
  Serial.print(topic);
  Serial.print("]: ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
}

void setup()
{
  pinMode (encoderCLK,INPUT_PULLUP);
  pinMode (encoderDT,INPUT_PULLUP);
  prvsCLK = digitalRead(encoderCLK);
  Serial.begin(115200);
  Serial.println();
  Serial.println();
  Serial.print("Attempting to connect to SSID: ");
  Serial.print(ssid);
  WiFi.hostname(HOSTNAME);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(1000);
  }
  Serial.println("connected!");

  Serial.print("Setting time using SNTP");
  configTime(1 * 3600, 0, "pool.ntp.org", "time.nist.gov");
  now = time(nullptr);
  while (now < 1510592825) {
    delay(500);
    Serial.print(".");
    now = time(nullptr);
  }
  Serial.println("done!");
  struct tm timeinfo;
  gmtime_r(&now, &timeinfo);
  Serial.print("Current time: ");
  Serial.print(asctime(&timeinfo));

  #ifdef CHECK_CA_ROOT
    BearSSL::X509List cert(digicert);
    net.setTrustAnchors(&cert);
  #endif
  #ifdef CHECK_PUB_KEY
    BearSSL::PublicKey key(pubkey);
    net.setKnownKey(&key);
  #endif
  #ifdef CHECK_FINGERPRINT
    net.setFingerprint(fp);
  #endif
  #if (!defined(CHECK_PUB_KEY) and !defined(CHECK_CA_ROOT) and !defined(CHECK_FINGERPRINT))
    net.setInsecure();
  #endif

  client.setServer(MQTT_HOST, MQTT_PORT);
  client.setCallback(receivedCallback);
  mqtt_connect();
}

void loop()
{
   crntCLK = digitalRead(encoderCLK);

 if (crntCLK != prvsCLK){
      // If the encoderDT state is different than the encoderCLK state then the rotary encoder is rotating counterclockwise
        if (digitalRead(encoderDT) != crntCLK) {
          servoAngle ++;

        }
        else {
          servoAngle --;
         }
         Serial.println(servoAngle);
          String myString = String(servoAngle);
          myString.toCharArray(ang, myString.length() + 1);
          client.publish(MQTT_PUB_TOPIC_angle, ang, false);
 }
  prvsCLK = crntCLK; 
  
  now = time(nullptr);
  if (WiFi.status() != WL_CONNECTED)
  {
    Serial.print("Checking wifi");
    while (WiFi.waitForConnectResult() != WL_CONNECTED)
    {
      WiFi.begin(ssid, pass);
      Serial.print(".");
      delay(10);
    }
    Serial.println("connected");
  }
  else
  {
    if (!client.connected())
    {
      mqtt_connect();
    }
    else
    {
      client.loop();
    }
  }

  if (millis() - lastMillis > 5000) {
    lastMillis = millis();
    client.publish(MQTT_PUB_TOPIC, ctime(&now), false);
  }
}

Arduino 3 servos using mqtt

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Servo.h> 
Servo lock1; 
Servo lock2;
Servo lock3;

const char* ssid = "MYSSID";                // WiFi SSID
const char* password = "MYSSIDPASS";        // WiFi Password
const char* mqtt_server = "MQTTSERVER";  // IP Broker MQTT
const char* topic_lock1 = "escape/servo/lock1";
const char* topic_lock2 = "escape/servo/lock2";
const char* topic_lock3 = "escape/servo/lock3";
 
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

void setup() {

  Serial.begin(115200);
  lock1.attach(D1);
  lock2.attach(D2);
  lock3.attach(D3);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
 String string;
 Serial.print("Message arrived [");
 Serial.print(topic);
 Serial.print("] ");
 for (int i = 0; i < length; i++) {
 string+=((char)payload[i]); 
 }
 Serial.print(string);
 Serial.print(" toInt ");
 int pos = string.toInt(); 
 Serial.println(pos);

 
 if ( strcmp(topic, topic_lock1) == 0 ) {
 Serial.print("lock1 ");
 Serial.println(pos);
 lock1.write(pos); 
 }
 if ( strcmp(topic, topic_lock2) == 0 ) {
 Serial.print("lock2 ");
 Serial.println(pos);
 lock2.write(pos); 
 }
 if ( strcmp(topic, topic_lock3) == 0 ) {
 Serial.print("lock3 ");
 Serial.println(pos);
 lock3.write(pos); 
 }
 
 delay(15); 
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP8266servolocks")) {
      Serial.println("connected");
      client.subscribe(topic_lock1); 
      client.subscribe(topic_lock2); 
      client.subscribe(topic_lock3); 
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}
void loop() {   
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  delay(100);
}

TM1637 7 Segment Module (with mqtt )

These tiny modules use a Clock and Data signal.
The rest of the pins are for 3.3V and Gnd.

There are many libraries you can choose from, i’ve tried several.
For now, i ended up with this one.

Another promising one is https://github.com/AKJ7/TM1637
Another one i’ve tested https://github.com/bxparks/AceSegment

Now i have to add Wifi and Mqtt so it can remotely controlled.

Connected like this

Code with Wifi/Mqtt

#include <Arduino.h>
#include <TM1637Display.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

const char* ssid = "MYSSID";
const char* password = "MYSSIDPASS";
const char* mqtt_server = "MQTT-SERVER-IP";
 
const int CLK = D6; //Set the CLK pin connection to the display
const int DIO = D5; //Set the DIO pin connection to the display
 
int numCounter = 0;
int mydata = 0;
 
// The amount of time (in milliseconds) between tests
#define TEST_DELAY   2000

const uint8_t SEG_DONE[] = {
  SEG_B | SEG_C | SEG_D | SEG_E | SEG_G,           // d
  SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,   // O
  SEG_C | SEG_E | SEG_G,                           // n
  SEG_A | SEG_D | SEG_E | SEG_F | SEG_G            // E
  };

TM1637Display display(CLK, DIO);

WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE  (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;


void setup()
{
 display.setBrightness(0x0a); //set the diplay to maximum brightness
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}


void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);


  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) {
  char buffer[4];
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    buffer[i] = int(payload[i]);
  }
  Serial.println();
//  mydata=int(payload[0])+int(payload[1]*10);
int  n;
n = atoi(buffer);

  display.showNumberDec(n); //Display the numCounter value;


}




void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("escape/seg1ping", "seg1alive");
      // ... and resubscribe
      client.subscribe("escape/seg1data");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void loop() {

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

  unsigned long now = millis();
  if (now - lastMsg > 2000) {
    lastMsg = now;
    ++value;
    snprintf (msg, MSG_BUFFER_SIZE, "seg1alive #%ld", value);
    Serial.print("Publish message: ");
    Serial.println(msg);
    client.publish("escape/seg1ping", msg);
  }
}

Connect the wires puzzle

As part of my internet based escape room.

I took the idea from the Keep-talking-and-nobody-explodes game.

When starting up, is gets the configuration from a Mqtt Topic.
So i can create a different setup over the internet.

The result is also send back via MQTT.

(example play, all players are on different locations)

  • Player 1 figures out the wires.
  • Player 2 connects the wires.
  • Player 3 sees the result (correct or not) and next puzzle opens up for Player 3

I used a wire with a line. Multiple colors for jacks and sockets.
It’s also possible to connect a jack to a jack.
Loads of possibilities.

Todo:

Wifi and Mqtt part
Debounce software or hardware