I just took a 12mm x 60mm piece of wood, and made a slit for the acrylic plastic using a circular saw, and removed a part for the back-plate using a wood router. I found a piece of acrylic in my shed, cut it to the right size using the circular saw. Slapped some paint on the wood.
I want to be able to use the sdk whenever i want, so i made a sliding window thingy. ( With wooden handle so the frame looks intact when closed. )
Then I 3D printed some holders, which I designed using Openscad.
The codes are entered using a keypad (Arduino) and send via MQTT
Node Red Dash board
Code
var code = global.get("mysetcode");
var good = 0;
var wrong = 0;
var wrongplace = 0;
var match = false;
var wrongchars = 0;
var wrongplaced = 0;
var goodchars = 0;
var payloadcode = msg.payload.toString();
var usr_input = Array.from(payloadcode);
var secret_code = Array.from(code);
var secret_code1 = secret_code;
if (msg.payload === code) {
match = true;
}
var result = "";
for (var i = 0; i < 4; i++) {
var found = false;
if (usr_input[i] === secret_code[i]) {
usr_input[i] = "a";
secret_code[i] = "b";
good = good + 1;
}
}
for (var i = 0; i < 4; i++) {
var found = false;
for (var j = 0; j < 4; j++) {
if (usr_input[i] === secret_code[j]) {
found = true;
}
}
if (!found) {
wrong = wrong + 1;
}
}
wrongchars = wrong - good;
wrongplaced = 4 - good - wrongchars;
msg.goodchars = good;
msg.wrongchars = wrongchars;
msg.wrongplace = wrongplaced;
msg.result = result;
msg.match = match;
return msg;
elcome to Crack the Code!
The code has 4 digits. Each digit is between 0 and 9.
You have 10 tries to guess the code.
After each guess, you will be told how many digits you got correct and how many were misplaced.
Good luck!
Enter your guess: 1234
Guess 1: 1234 - 0 correct, 0 misplaced
Enter your guess: 5678
Guess 2: 5678 - 2 correct, 1 misplaced
Enter your guess: 5689
Guess 3: 5689 - 1 correct, 2 misplaced
Enter your guess: 9688
Guess 4: 9688 - 1 correct, 2 misplaced
....
Sorry, you did not crack the code. The code was 5568.
Generated python code
import random
def generate_code():
code = ""
for i in range(4):
code += str(random.randint(0, 9))
return code
def check_guess(code, guess):
correct_digits = 0
misplaced_digits = 0
for i in range(4):
if guess[i] == code[i]:
correct_digits += 1
elif guess[i] in code:
misplaced_digits += 1
return (correct_digits, misplaced_digits)
def play_game():
print("Welcome to Crack the Code!")
print("The code has 4 digits. Each digit is between 0 and 9.")
print("You have 10 tries to guess the code.")
print("After each guess, you will be told how many digits you got correct and how many were misplaced.")
print("Good luck!")
code = generate_code()
num_guesses = 0
while num_guesses < 10:
guess = input("Enter your guess: ")
if len(guess) != 4 or not guess.isdigit():
print("Invalid input. Please enter a 4-digit number.")
continue
num_guesses += 1
correct, misplaced = check_guess(code, guess)
print(f"Guess {num_guesses}: {guess} - {correct} correct, {misplaced} misplaced")
if correct == 4:
print("Congratulations! You cracked the code!")
return
print(f"Sorry, you did not crack the code. The code was {code}.")
play_game()
After this i let the AI made some changes, which kinda worked. Scary nevertheless
I’ve build a IR Blaster in the past and tested IR with EspEasy Dev. I’m not happy with my Harmony Hub. Not so much control as i like to have.
So now OpenMqttGateway with IR.
Wemos D1 with IR shieldIR Signal (visible using mobile phone)
I’ve installed platformio in the past. Not really a fan of visual-code i’m showing you the process on CLI
We can’t use the webinstaller or a precompiled binary because we need to change GPIO ports
wget https://github.com/1technophile/OpenMQTTGateway/releases/download/v1.5.0/nodemcuv2-ir-libraries.zip
wget https://github.com/1technophile/OpenMQTTGateway/archive/refs/tags/v1.5.0.tar.gz
tar xzvf v1.5.0.tar.gz
cd v1.5.0/libs
unzip ../../nodemcuv2-ir-libraries.zip
cd ..
edit platformio.ini
remove ; from
default_envs = nodemcuv2-ir
vi main/config_IR.h
search for LOLIN, edit and change into 0 (GPIO 0 = D3)
build and upload
pio run --target upload --upload-port /dev/ttyUSB0
build and upload with flash erase
pio run --target erase --target upload --upload-port /dev/ttyUSB0
clean the environment when needed
pio run -t clean
Now you will get a Access Point, connect and enter your Wifi network information and mqtt server.
When connected you will see the IR codes and if you installed mqtt support in home assistant it will see the mqtt topics.
I’ve copied a json output as was send by my IR remote. Below an example using mosquitto_pub to send codes.
Why use platformio? I know Arduino IDE is easier for starters. Platformio is far more flexible, you can make projects with their own versions of libraries. I like CLI, easier to do version control (git)
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.
Created a virtual machine with Ghostpath VPN. I can re-direct other machines in my network to use this gateway.
Next to do: Filter HTTP headers/cookies and implement proxychains.
My webscrapers, Transmission and Sabnzb are configured to use this VPN gateway. I stopped using docker instances for this, to much hassle to keep these images working.
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()
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);
}
}
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