Escape Room je zaujímavý spôsob trávenia času a zábavy. Dokáže potrápiť mozgové závity pri hlavolamoch, číslicových úlohách riešením ktorých hráči postupujú v hre. Rozhodol som sa do Escape Room vložiť aj interaktívny spôsob zadávania číselného kódu v miestnosti. Arduino obsuluhe päticu tlačidiel, prostredníctvom ktorých je možné zasielať/meniť čísla (záleží od konkrétnej implementácie). Tlačidlá sú debouncované cez funkciu časovača millis(); s dobou debouncu (ošetrenia zákmitov tlačidla) 50 ms. Metóda vstupu tlačidiel je v počiatočnej hodnote INPUT_PULLUP, kedy sú interným pullup rezistorom pripojené na 5V. Spínajú sa proti zemi. Využívajú sa spínacie tlačidlá, nie rozpínacie.
LCD displej slúži na reprezentáciu zadaných čísel od používateľa s ich vizualizáciou v reálnom čase. Je možné využiť LCD 20x4/16x2 s I2C prevodníkom. Výpis sa realizuje len na 2 riadky.
Displej vypisuje aj adresu na LAN sieti, čím indikuje konektivitu, alebo problém na sieti. Na Arduine je nasunutý Ethernet shield W5100 od Wiznetu, ktorý po HTTP protokole komunikuje po sieti s webserverom, ktorému predáva zadané číslo od používateľa.
Dáta sú predávané POST metódou. Odpoveďou servera je payload s potvrdením/zamietnutím prijatého čísla.
Potvrdenie sa vykoná v prípade uhádnutia správneho kódu. Výsledkom potvrdenia je odomknutie dverí prostredníctvom elektromagnetického relé, ktoré ovláda solenoidový zámok dverí. Je možné využiť aj SSR relé v prípade, že solenoidový zámok dverí je na striedavé napätie. (SSR relé majú problém s rozopnutím obvodu s jednosmerným napätím - viz. triak v často používanom relé OMRON G3MB-202P.) Relé sa spína obrátenou logikou, t.j. active low. Pri signále 5V (log 1) je relé rozopnuté, pri 0V (log 0) zopnuté a solenoidový zámok otvorený. V prípade neuhádnutého čísla sa indikuje na displeji/prídavnou LED diódou chyba pre používateľa so zadaním chybného číselného kódu.
Webové rozhranie pre administrátora obsahuje login systém s možnosťou zmeny údajov a možnosť zmeniť hľadané číslo pre všetky 3 herné módy, ktoré sú podporované. Prvý mód obsahuje zaslanie jedného čísla tlačidlami 1-5. Stlačením tlačidla sa ihneď odošle HTTP POST request na webserver a ten odpovie s výsledkom overenia do payloadu. Existuje iba 5 možných kombinácii, hľadanie je rýchle. Tento herný mód nie je vybavený displejom.
Druhý herný mód využíva zadanie štyroch čísel s možnosťou opakovania, t.j. z rozsahu 0000-9999. Celkom teda existuje 10 000 kombinácii, pričom len jedna je správna. Štyri tlačidla slúžia na nastavenie čísel. Každé tlačidlo obsluhuje svoju pozíciu inkrementovaním čísla od 0-9. Piatej tlačidlo slúži ako Enter a po jeho stlačení sa zadaná štvorkombinácia odošle do webového rozhrania.
Tretím mód je takmer totožný ako druhý, funguje bez opakovania čísel. Celkovo existuje 5040 možných kombinácii s jednou správnou.
Všetky 3 herné módy môžu byť obsluhované z jedného webového rozhrania. Administrátor dokáže navoliť hľadané číslo pre každú hru. Zmena je aplikovaná okamžite (aj počas hry). Webové rozhranie je možné ďalej doplniť o použitie MySQL databázy na jednotlivé pripojenia od Arduina. Použitie pre účely štatistiky, úspešnosti súťažiacich so záznamom zadaných čísel, počtu pokusov, časové obdobie. Webová stránka je ošetrená na vstupy čísel pre každý z herných módov (zohľadňuje opakovanie, neopakovanie, dĺžku číselného kódu).
Ako mikrokontróler je možné použiť aj ESP32, ESP8266 s WiFi konektivitou. Podporujú aj HTTPS šifrované spojenie s webovou lokalitou. Pre ESP32 je možné použiť vlastnú certifikačnú autoritu, HTTPS certifikát. Projekt je reálne nasadený a jedná sa o platené riešenie ku ktorému som schopný dodať softvér, schému zapojenia. Súčasťou tohto článku je jeden kód pre Arduino a Ethernet W5100, ktorý v okresanej verzii ponúka časť prvého herného módu s hľadaním jedného čísla. Číslo je napevno definované v .php súbore webovej stránky na ktorú sa Arduino s Ethernet shieldom pripája, neobsahuje pripojenie na databázu, admin rozhranie. Platená verzia obsahuje aj integrovaný watchdog, ktorý Arduino reštartuje v prípade zaseknutia.
Ďalšie projekty je možné nájsť na mojej stránke:
https://arduino.php5.sk/Schéma zapojenia pre všetky 3 herné módy:Program pre Arduino:Kód:
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = { 0xAA, 0xBB, 0xCC, 0xAA, 0xBB, 0xCC };
IPAddress ip(192, 168, 1, 101);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
char serverName[] = "192.168.1.254"; //or hostname
int serverPort = 80;
const int buttonPin1 = 9;
const int buttonPin2 = 8;
const int buttonPin3 = 7;
const int buttonPin4 = 6;
const int buttonPin5 = 5;
const int relay = 3;
int buttonState1 = HIGH;
int buttonState2 = HIGH;
int buttonState3 = HIGH;
int buttonState4 = HIGH;
int buttonState5 = HIGH;
int lastButtonState1 = HIGH;
int lastButtonState2 = HIGH;
int lastButtonState3 = HIGH;
int lastButtonState4 = HIGH;
int lastButtonState5 = HIGH;
unsigned long lastDebounceTime1 = 0;
unsigned long lastDebounceTime2 = 0;
unsigned long lastDebounceTime3 = 0;
unsigned long lastDebounceTime4 = 0;
unsigned long lastDebounceTime5 = 0;
unsigned long debounceInterval = 50;
EthernetClient client;
int number = 0;
String url = "/sendnumber.php";
void setup() {
Serial.begin(115200);
pinMode(relay, OUTPUT);
digitalWrite(relay, HIGH); //lock door
pinMode(buttonPin1, INPUT_PULLUP);
pinMode(buttonPin2, INPUT_PULLUP);
pinMode(buttonPin3, INPUT_PULLUP);
pinMode(buttonPin4, INPUT_PULLUP);
pinMode(buttonPin5, INPUT_PULLUP);
Ethernet.begin(mac, ip, gateway, gateway, subnet);
Serial.println("IP address set to Ethernet shield:");
Serial.println(Ethernet.localIP());
delay(2000);
Serial.println("Ready");
}
void send_datas() {
String my_datas = String(number);
String data = "number=" + my_datas;
if (client.connect(serverName, serverPort)) {
client.println("POST " + url + " HTTP/1.0");
client.println("Host: " + (String)serverName);
client.println("User-Agent: ArduinoEthernetWiznet");
client.println("Connection: close");
client.println("Content-Type: application/x-www-form-urlencoded;");
client.print("Content-Length: ");
client.println(data.length());
client.println();
client.println(data);
while (client.connected()) {
//HTTP HEADER
String line = client.readStringUntil('\n'); //HTTP header
if (line == "\r") {
break; //blank line between HTTP header and payload
}
}
String line = client.readStringUntil('\n'); //Payload first line
if (line == "Access") {
Serial.println("Access gained!");
digitalWrite(relay, LOW); //unlock door to next level
} else {
Serial.println("Access denied!");
digitalWrite(relay, HIGH); //lock door
}
} else {
Serial.println("Error connecting to webserver!");
}
client.stop();
}
void loop() {
int reading1 = digitalRead(buttonPin1);
int reading2 = digitalRead(buttonPin2);
int reading3 = digitalRead(buttonPin3);
int reading4 = digitalRead(buttonPin4);
int reading5 = digitalRead(buttonPin5);
if (reading1 != lastButtonState1) {
lastDebounceTime1 = millis();
}
if (reading2 != lastButtonState2) {
lastDebounceTime2 = millis();
}
if (reading3 != lastButtonState3) {
lastDebounceTime3 = millis();
}
if (reading4 != lastButtonState4) {
lastDebounceTime4 = millis();
}
if (reading5 != lastButtonState5) {
lastDebounceTime5 = millis();
}
if ((millis() - lastDebounceTime1) > debounceInterval) {
if (reading1 != buttonState1) {
buttonState1 = reading1;
if (buttonState1 == HIGH) {
number = 1;
send_datas();
}
}
}
if ((millis() - lastDebounceTime2) > debounceInterval) {
if (reading2 != buttonState2) {
buttonState2 = reading2;
if (buttonState2 == HIGH) {
number = 2;
send_datas();
}
}
}
if ((millis() - lastDebounceTime3) > debounceInterval) {
if (reading3 != buttonState3) {
buttonState3 = reading3;
if (buttonState3 == HIGH) {
number = 3;
send_datas();
}
}
}
if ((millis() - lastDebounceTime4) > debounceInterval) {
if (reading4 != buttonState4) {
buttonState4 = reading4;
if (buttonState4 == HIGH) {
number = 4;
send_datas();
}
}
}
if ((millis() - lastDebounceTime5) > debounceInterval) {
if (reading5 != buttonState5) {
buttonState5 = reading5;
if (buttonState5 == HIGH) {
number = 5;
send_datas();
}
}
}
lastButtonState1 = reading1;
lastButtonState2 = reading2;
lastButtonState3 = reading3;
lastButtonState4 = reading4;
lastButtonState5 = reading5;
}
-----------------------------------------------------------------------------------------------------------------
Program pre webserver (PHP) sendnumber.php:Kód:
<?php
$secret_number = 3;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$number = $_POST['number'];
$number = trim( $number );
if (is_numeric($number)){
if($number==$secret_number){
echo "Access";
}else{
echo "Problem";
}
}
}else{
echo "Unsupported METHOD! Use POST instead of GET/PUT/PATCH!";
}
?>