Red – Green Machine v2 – Web

Red-Green Machine sklidila úspěch, ale jejím omezením bylo možnost použití jen lidmi v dosahu. Nedostatek jsem chtěl odstranit možností ovládání přes webový prohlížeč.

1. Nové obzory

Na Arduinu jsem už webový server používal. Jeho implementace je jednoduchá. S čím jsem, ale neměl zkušenost bylo připojení přez WiFi. Všechny projekty používaly Mini Ethernet modul HanRun s cenou kolem 100,- Kč. Cena Wifi shieldu se pohybuje kolem 300,- Kč.

Vzpomněl jsem si, že mi kamarád vyprávěl o použití NodeMCU pro  snímání a odesílání teploty. Deska umožňuje programování v Lua nebo v kódu pro Android. A to nejlepší na závěr je její cena, včetně WiFi modulu, kolem 80,- Kč.

Další zajímavá komponenta, na kterou jsem narazil je mini Mp3 přehrávač DFPlayer mini s 3W zesilovačem a slotem pro SD kartu za cenu 50,- Kč.

Nějak mimochodem jsem přišel na existenci PullUp rezistorů 20k zabudovaných přímo v Atmega čipech. Takže odpadá nutnost rezistorů pro tlačítka. Jejich použití je jednoduché.

pinMode(PIN_RED, INPUT_PULLUP);

2. Komponenty

3. Jak to funguje

Na kartě jsou dva adresáře „00“ pro red hlášky a „01“ pro green hlášky. V každém jsou uloženy zvukové soubory s 4 místným číselným prefixem. Soubory jsou ve formátu wav 16Hz, 8bit mono. Při stisku tlačítka se náhodně vybere jeden ze souborů ve zvoleném adresáři a přehraje se.

Po přihlášení do WiFi sítě, získáme IP adresu RedGreenMachine a tu zadáme do webového prohlížeče. Načte se nám jednoduchá stránka s popisem a virtuálními red a green tlačítky.

Pro zelené tlačítko jsou použity superlativy z Apple KeyNote a pro červené tlačítko „Lakatoš“.

RedGreenMachineWeb_pack

4. Krabička

Rozložená krabička s vruty a průchodkami.
Mechanické komponenty.

Do horního dílu krabičky si pro tlačítka a reproduktor vyvrtáme díry.

Vyvrtané díry v krabičce.

Díry pečlivě začistíme pilníkem. Do spodního dílu, si pod díru pro reproduktor vybrousíme štěrbinu pro vložení micro SD karty.

Vstup pro mikro SD kartu.

Reproduktor vlepíme pomocí tavné pistole. Tlačítka přišroubujeme maticemi.

Instalovaný reproduktor a tlačítka.

5. Instalace NodeMcu a Mp3

Abychom vyrovnali výšku mezi vstupem pro kabel a konektorem NodeMcu, tak desku podložíme 5 mm překližkou, kterou přilepíme tavnou pistolí. Překližku zároveň použijeme k zajištění Mp3 přehrávače u štěrbiny pro micro SD kartu. Mp3 modul pro jistotu ještě přilepíme ke spodnímu dílu krabičky. Dáváme pozor, ať nezalepíme SD slot.

Překližka zajišťuje Mp3 modul a bude sloužit k připevnění NodeMcu.

K NodeMcu připojíme tlačítka a k Mp3 modulu reproduktor. Ledky tlačítek připojíme přes odpory 220Ohm.

Připojení tlačítek k NodeMcu.
Kompletní propojení.

6. Program

#include <ESP8266WiFi.h>
#include <SoftwareSerial.h>
#include <DFPlayer_Mini_Mp3.h>

#define VERSION 0.06
// 0.06 - Not required Wifi connection
// 0.05 - Support for leds.
// 0.04 - Support for buttons, show info on webpage
// 0.03 - Support for volume and specific file playing
// 0.02 - Mp3 modul test
// 0.01 - Web test

#define PIN_RED D3
#define PIN_GREEN D4
#define PIN_BUSY D5
#define PIN_RED_LED D6
#define PIN_GREEN_LED D7

#define RED_FOLDER_NUMBER 0//folder name is 00
#define GREEN_FOLDER_NUMBER 1//folder name is 01

#define DELAY_BETWEEN_WIFI_RECONNECTION 6000//in ms

const char* ssid = "";//wifi SSID name
const char* password = "";//wifi password

int mp3Volume = 20;//default volume
int redFileCount = 0;//file count in directory 00 - red
int greenFileCount = 0;//file count in directory 01 - green

bool wifiConnected = false;
uint32_t timeToTryConnectToWifi;

WiFiServer server(80);//server will run on port 80
SoftwareSerial mp3Serial(D1, D2);// RX, TX
 
void setup()
{
  Serial.begin(115200);
  delay(10);

  connectToWifi(30);
  
  //set software serial
  mp3Serial.begin(9600);

  //set mp3 player
  pinMode(PIN_BUSY, INPUT);
  
  mp3_set_serial(mp3Serial);
  mp3_set_debug_serial(Serial);

  // Delay is required before accessing player. From my experience it's ~1 sec
  delay(1000);

  mp3_set_volume(mp3Volume);//0 - 30
  mp3_set_device(2);//set source SD card

  //read file counts
  mp3_get_folder_sum(RED_FOLDER_NUMBER);
  redFileCount = mp3_wait_folder_sum();

  Serial.print("redFileCount:");
  Serial.println(redFileCount);

  mp3_get_folder_sum(GREEN_FOLDER_NUMBER);
  greenFileCount = mp3_wait_folder_sum();

  Serial.print("greenFileCount:");
  Serial.println(greenFileCount);

  //prepare buttons
  pinMode(PIN_RED, INPUT_PULLUP);
  pinMode(PIN_GREEN, INPUT_PULLUP);

  //prepare leds
  pinMode(PIN_RED_LED, OUTPUT);
  pinMode(PIN_GREEN_LED, OUTPUT);

  randomSeed(analogRead(0));//initialize random generator from analog input
}
 
void loop()
{
  checkButtonsState();   
  checkWebServerStatus();
}

// Try connect to wifi and start server
void connectToWifi(int maxTry)
{
  // Connect to WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
 
  WiFi.begin(ssid, password);

  int wifiConnectionTryCount = 0;
  while (WiFi.status() != WL_CONNECTED && wifiConnectionTryCount < maxTry)
  {
    delay(500);
    Serial.print(".");
    wifiConnectionTryCount++;
  }

  //set flag according to wifi status
  wifiConnected = WiFi.status() == WL_CONNECTED;

  if (wifiConnected)
  {
    Serial.println("WiFi connected");
   
    // Start the server
    server.begin();
    Serial.println("Server started");
   
    // Print the IP address
    Serial.print("Use this URL to connect: ");
    Serial.print("http://");
    Serial.print(WiFi.localIP());
    Serial.println("/");
  }
  else
  {
    Serial.println("WiFi not connected");
  }
}

// Test if some button is pressed
void checkButtonsState()
{
  int buttonState = digitalRead(PIN_RED);
  if (buttonState == LOW)
  {
    Serial.print("Red button:");
    Serial.println(" pressed");

    digitalWrite(PIN_RED_LED, HIGH);
    playRandom(RED_FOLDER_NUMBER, redFileCount);
  }
  else
  {
    digitalWrite(PIN_RED_LED, LOW);
  }

  buttonState = digitalRead(PIN_GREEN);
  if (buttonState == LOW)
  {
    Serial.print("Green button:");
    Serial.println(" pressed");

    digitalWrite(PIN_GREEN_LED, HIGH);
    playRandom(GREEN_FOLDER_NUMBER, greenFileCount);
  }
  else
  {
    digitalWrite(PIN_GREEN_LED, LOW);
  }
}

// Test if some web request is available
void checkWebServerStatus()
{
  if (!wifiConnected)
  {
    uint32_t nowTime = millis();

    //check time to try connect to wifi
    if (nowTime > timeToTryConnectToWifi)
    {
      connectToWifi(20);

      timeToTryConnectToWifi = nowTime + DELAY_BETWEEN_WIFI_RECONNECTION;
    }

    //check last status
    if (!wifiConnected)
    {
      return;
    }
  }
  
// Check if a client has connected
  WiFiClient client = server.available();
  if (!client)
  {
    return;
  }

  int waitCounter = 0;
  
  // Wait until the client sends some data
  Serial.println("new client");
  while(!client.available())
  {
    delay(1);
    waitCounter++;

    if (waitCounter > 100)
    {
      client.flush();
      return;
    }
  }
 
  // Read the first line of the request
  String request = client.readStringUntil('\r');
  client.flush();

  processRequest(request);

  // Return the response
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println(""); //  do not forget this one
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");

  client.println("<br><br>");
  client.println("<a href=\"/button=red\"\"><button style=\"background-color:red\">Red </button></a>");
  client.println("<a href=\"/button=green\"\"><button style=\"background-color:green\">Green </button></a><br />");

  client.print("<br><br>RGM version:");
  client.println(VERSION);
  
  client.print("<br>Red files count:");
  client.println(redFileCount);

  client.print("<br>Green files count:");
  client.println(greenFileCount);
  
  client.print("<br>Actual volume is now:");
  client.println(mp3Volume);

  client.println("<br><br>");
  client.println("button=Green - plays random green sfx");
  client.println("<br>playGreen=1 - plays green sfx with index 1");
  
  client.println("</html>");
 
  delay(1);
  Serial.println("Client disonnected");
  Serial.println("");
}

// Process web request and process commands
void processRequest(String request)
{
  Serial.print("Process request:");
  Serial.println(request);
  
  // Match the request
  if (request.indexOf("/button=red") != -1) 
  {
    Serial.println("Red button sended");

    playRandom(RED_FOLDER_NUMBER, redFileCount);
  }
  else if (request.indexOf("/button=green") != -1) 
  {
    Serial.println("Green button sended");

    playRandom(GREEN_FOLDER_NUMBER, greenFileCount);
  }
  else if (request.indexOf("/playRed=") != -1)
  {
    int index = request.indexOf("=");
    String fileNumberString = request.substring(index + 1);
    int fileNumber = fileNumberString.toInt();
    if (fileNumber >= redFileCount)
    {
      fileNumber = redFileCount - 1;//use last as default
    }

    playFileIndex(RED_FOLDER_NUMBER, fileNumber);
  }
  else if (request.indexOf("/playGreen=") != -1)
  {
    int index = request.indexOf("=");
    String fileNumberString = request.substring(index + 1);
    int fileNumber = fileNumberString.toInt();
    if (fileNumber >= greenFileCount)
    {
      fileNumber = redFileCount - 1;//use last as default
    }
    
    playFileIndex(GREEN_FOLDER_NUMBER, fileNumber);
  }

  //volume settings
  int volumeIndex = request.indexOf("/volume=");
  if (volumeIndex != -1) 
  {
    String volumeString = request.substring(volumeIndex + 8);
    int newVolume = volumeString.toInt();

    if (newVolume > 0 && newVolume <= 30)
    {
      mp3Volume = newVolume;
      
      Serial.print("Change volume to:");
      Serial.println(mp3Volume);

      mp3_set_volume(mp3Volume);
    }
  }
}

// Play random file in selected folder and range
void playRandom(int folderNumber, int fileCount)
{
  int randomFileIndex = random(fileCount);
  playFileIndex(folderNumber, randomFileIndex);
}

// Play selected file in selected folder
void playFileIndex(int folderNumber, int fileIndex)
{
  mp3_stop();
  mp3_play_file_in_folder(folderNumber, fileIndex);
}

7. Kontrola funkčnosti

Před zakrytováním zkontrolujeme funkčnost tlačítek a reproduktoru. Případný problém najdeme a odstraníme.

Krabičku zašroubujeme a nezapomeneme na plastové nožičky.

Hotovo.

Připojíme ke zdroji a počkáme až naběhne. V zápětí vyzkoušíme obě tlačítka. Pro zkoušku webového rozhraní budeme potřebovat zjisti IP adresu RedGreenMachine. Tu zjistíme pomocí AdvancedIPScanner nebo Fing. Najdeme ji také v konzoli po připojení k wifi.

RedGreenMachine web page.

 

Nezávislá RedGreenMachine.
Porovnání obou verzí.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *

Proudly powered by WordPress | Theme: Baskerville 2 by Anders Noren.

Up ↑