Toilet Time

Ignorat sau râvnit, tihnit sau zbuciumat, relaxare sau chiar plăcut timp de lectură… putem descrie în multe moduri timpul petrecut la toaletă dar știm de fapt care este acest timp? În cadrul proiectului de față vom prezenta realizarea unui sistem ce permite măsurarea timpului petrecut la toaletă. Chiar dacă poate părea puțin bizară tematica propusă vă asigurăm că mulți pasionați de sisteme electronice programabile s-au gândit cel puțin o dată la un sistem care să accesorizeze toaleta proprie; câteva exemple de astfel de proiecte:

Sistemul propus de noi se bazează pe o placă de dezvoltare Adafruit Feather HUZZAH echipată cu microprocesorul WiFi ESP8266. Conectivitatea WiFi va permite consultarea timpului total petrecut la toaletă prin intermediul oricărui dispozitiv inteligent cu conectivitate de rețea (tabletă, telefon mobil). În plus, specific tuturor plăcilor din familia Feather, placa de dezvoltare se poate alimenta de la un acumulator LiPo de 3.7V permițând crearea simplă a unui sistem independent de alimentarea USB. Detectarea ocupării toaletei se va face cu ajutorul unui buton brick ce se va poziționa sub colacul toaletei. Greutatea colacului nu este suficientă pentru a apăsa butonul, butonul se va apăsa doar dacă toaleta este ocupată. Bineînțeles, se poate înlocui componenta buton brick cu un senzor de apăsare brick dacă se dorește perfecționarea dedectării ocupării toaletei sau dacă se dorește realizarea unui sistem cu mai mulți ”utilizatori”.

Schema de interconectare dintre placa de dezvoltare și brick-ul buton este următoarea:

2

Brick-ul se va alimenta la 3.3V iar ieșirea se va conecta la pinul GPIO12 al plăcii de dezvoltare.

Programul a fost dezvoltat și testat utilizând Arduino IDE 1.8.5 având instalată extensia ESP8266 Community 2.3.0. În cadrul programului trebuie personalizate datele de conectare WiFi (variabilele ssid și password).

#include <ESP8266WiFi.h>

#include <WiFiClient.h>

#include <ESP8266WebServer.h>

#include <EEPROM.h>

const char *ssid = “…”;

const char *password = “…”;

ESP8266WebServer server (80);

#define pinButton 12

Timpul total de utilizarea a toaletei este stocat în variabila globală toilettime ca număr de secunde. Consultarea timpului total se poate face accesând adresa IP a sistemului (oferită prin DHCP de către AP-ul WiFi) dintr-un client web (browser web). Procedura handleRoot() este responsabilă de construirea paginii HTML trimisă către clientul web. Timpul total se va afișa în format HH:MM:SS. Programul poate fi îmbunătățit în această privință pentru a afișa durate mai mari de timp (sub formă de zile, săptămâni, ani).

3

char temp[600];

unsigned long toilettime;

void handleRoot() {

int sec = toilettime % 60;

int min = (toilettime / 60) % 60;

int hr = toilettime / 3600;

snprintf ( temp, 600,”%02d:%02d:%02d”, hr, min, sec);

String page = “<html>\

<head>\

<meta http-equiv=’refresh’ content=’10’/>\

<title>Toillet Time</title>\

<style>\

body { background-color: #cccccc; font-family:

Arial, Helvetica, Sans-Serif; Color: #000088; }\

</style>\

</head>\

<body>\

<h1>Toilet Time</h1>\

<p><b>Your total time is:</b> ” + String(temp) + “

</p>\

</body>\

</html>”;

page.toCharArray(temp,page.length()+1);

server.send ( 200, “text/html”, temp );

}

Variabila ocupat are semnificația de toaletă ocupată. Când variabila ocupat are valoare true sistemul va contoriza timpul scurs și îl va adăuga la variabila toilettime. Conținutul variabilei toilettime se va salva în memoria flash a plăcii de dezvoltare la fiecare trecere din true în false a variabilei ocupat – acest lucru va asigura păstrarea timpului total și după un reset al plăcii de dezvoltare. Pentru operațiile cu memoria flash programul utilizează biblioteca Arduino IDE EEPROM. Placa de dezvoltare nu are memorie EEPROM, versiunea pentru ESP8266 a bibliotecii EEPROM utilizează aceleași funcții și metode ca la plăcile Arduino dar se folosește de memoria program flash. În cadrul secțiunii setup(), la fiecare nouă inițializare a programului, variabila toilettime se inițializează din memoria non-volatilă program.

boolean ocupat;

void setup() {

pinMode(pinButton, INPUT);

EEPROM.begin(512);

toilettime = 0;

toilettime += (long)EEPROM.read(0)<<24;

toilettime += (long)EEPROM.read(1)<<16;

toilettime += (long)EEPROM.read(2)<<8;

toilettime += (long)EEPROM.read(3);

WiFi.begin ( ssid, password );

while ( WiFi.status() != WL_CONNECTED ) {

delay ( 500 );

}

server.on ( “/”, handleRoot );

server.begin();

ocupat = false;

}

Variabilele start și stopp memorează momentele trecerii variabilei ocupat din false în true (așezarea pe toaletă) și din true în false (ridicarea de pe toaletă). În momentul adunării timpului scurs la variabila globală toilettime, conținutul acesteia este salvată și în memoria flash.

unsigned long start, stopp;

void loop() {

if ((!ocupat) && (digitalRead(pinButton)==1)) {

start = millis();

ocupat = true;

}

if (ocupat && (digitalRead(pinButton)==0)) {

stopp = millis();

ocupat = false;

toilettime += (stopp – start)/1000;

byte temp;

temp = (toilettime>>24) & 0xFF;

EEPROM.write(0, temp);

temp = (toilettime>>16) & 0xFF;

EEPROM.write(1, temp);

temp = (toilettime>>8) & 0xFF;

EEPROM.write(2, temp);

temp = toilettime & 0xFF;

EEPROM.write(3, temp);

EEPROM.commit();

}

server.handleClient();

}

În cazul în care vă plictisiți testând sistemul vă recomandăm aplicația mobilă Android Toilet Time – Mini-games for the bathroom.

Mini Stație Meteo Weather Underground

Serviciul Weather Undergroud este un serviciu independent (nu este un serviciu al unei țări sau strucutură oficială) de predicție a vremii. Acest serviciu Internet permite realizarea de prognoze locale pe baza informațiilor provenite de la o stație meteo personală (PWS – Personal Wether Station) sau corelând informațiile de la mai multe stații meteo personale aflate într-o anumită zonă. Serviciul Weather Underground permite completarea funcționalității unei stații meteo personale cu partea de istoric și predicție a evoluției vremii și oferă o modalitate convenabilă în care utilizatorul poate consulta informațiile furnizate de stația meteo de oriunde prin Internet.

În cadrul proiectului de față vom prezenta realizarea unei mini stații meteo (măsoară doar temperatura, umiditatea și presiunea atmosferică) ce raportează datele măsurate către serviciul Weather Underground. Pentru partea de achiziție vom utiliza un singur senzor capabil să măsoare toți cei trei parametrii: BME280. Bineînțeles, sistemul prezentat poate fi extins și cu alți senzori specifici unei stații meteo: senzori pentru viteza și direcția vântului, senzor pentru cantitatea de precipitații sau senzor pentru indexul radiațiilor ultraviolete.

2

Ca placă de dezvoltare vom utiliza Adafruit HUZZAH ESP8266 breakout ce ne va permite o conectare simplă la Internet prin WiFi la un cost scăzut. Schema de interconectare între placa de dezvoltare și senzorul BME280 este următoarea:

3

Comunicația între senzor și placa de dezvoltare se bazează pe protocolul I2C prin urmare legărutile sunt:

  • Pinul SDA al senzorului se conectează la pinul #4 al plăcii de dezvoltare;
  • Pinul SCL al senzorului se conectează la pinul #5 al plăcii de dezvoltare;
  • Pinii 3.3V și GND ai senzorului se conectează la pinii 3V și GND ai plăcii.

Placa va trimite la un interval de 60 de minute (1 oră) datele achiziționate către serviciul Weather Underground iar între două postări se va afla în mod de consum redus. Din acest motiv există o legătură între pinul #16 și pinul RST al plăcii. Pinul #16 are funcționalitate de Wake ce permite resetarea plăcii pentru a ieși din modul de consum redus. Pentru mai multe informații despre modul de consum redus al circuitului ESP8266 puteți consulta materialul „ESP8266 Deep Sleep with Arduino IDE”.

Pentru alimentarea plăcii puteți un regulator de 3.3V sau una sau mai multe baterii ce furnizează între 4V și 6V (alimentarea se va face în acest caz prin intermediul pinului Vbat). Având în vedere consumul redus al sistemului funcționarea pe baterii se poate face pe perioade lungi de timp.

Pentru programarea plăcii Adafruit HUZZAH ESP8266 este nevoie de un programator FTDI sau de un cablu FTDI. Pentru mai multe informații despre funcționarea plăcii de dezvoltare Adafruit HUZZAH ESP8266 puteți consulta materialul „Adafruit HUZZAH ESP8266 breakout – Adorable bite-sized WiFi microcontroller, at a price you like!”.

Programul a fost dezvoltat și testat utilizând Arduino IDE 1.8.3 având instalate extensia ESP8266 Community 2.3.0 și biblioteca Sparkfun BME280 1.1.0. În cadrul programului trebuie personalizate datele de conectare la rețeaua WiFi (ssid și pass) precum și datele de autentificare la platforma Weather Underground (ID și PASSWORD).

#include <ESP8266WiFi.h>

#include <ESP8266HTTPClient.h>

#include “SparkFunBME280.h”

#include “Wire.h”

BME280 mySensor;

char ssid[] = “…”;

char pass[] = “…”;

WiFiClient client;

void setup() {

  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {

      delay(500);

    }

  mySensor.settings.commInterface = I2C_MODE;

  mySensor.settings.I2CAddress = 0x77;

  mySensor.settings.runMode = 3;

  mySensor.settings.tStandby = 0;

  mySensor.settings.filter = 0;

  mySensor.settings.tempOverSample = 1;

  mySensor.settings.pressOverSample = 1;

  mySensor.settings.humidOverSample = 1;

  mySensor.begin();

  delay(100); }

void loop() {

  float tempC = mySensor.readTempC();

  float humidity = mySensor.readFloatHumidity();

  float pressure = mySensor.readFloatPressure();

  delay(100);

  String url = “http” + “://weatherstation.wunderground.com/”

  url += “weatherstation/updateweatherstation.php?”

  url += “ID=…&PASSWORD=…”

  url += “&dateutc=now&=&action=updateraw&”;

  url += “baromin=” + String(pressure * 29.92 / 101325);

  url += “&tempf=” + String(9/5.0 * tempC + 32.0);

  url += “&humidity=” + String(humidity);

  url += “&dewptf=” + String(9/5.0 * (tempC – (100.0 –

humidity) /5.0) + 32.0);

  HTTPClient http;

  http.begin(url);

  int httpCode = http.GET();

  delay(1000);

  http.end();

  delay(1000);

  ESP.deepSleep(3600L*1000000L);  }

Așa cum am precizat și anterior, serviciul Weather Underground este un serviciu independent de prognoză meteorologică bazată în principal de rețele de stații meteo proprii (în SUA) sau private (PWS – Personal Weather Station, în restul lumii). Platforma online a acestui serviciu permite înregistrarea datelor provenite de la orice PWS și realizarea de prognoze de evoluție a vremii zonale ca o alternativă mult mai rafinată la serviciile naționale de meteorologie. Serviciul este gratuit dar necesită înregistrare. Un utilizator poate înregistra mai multe stații meteo aflate în locații diferite. Imediat după înregistrarea stației meteo personale se poate porni sistemul și datele înregistrate vor apărea imediat în fereastra asociată stației respective.

4

După o perioadă de 24 – 48 de ore, dacă datele raportate sunt valide – se încadrează într-un interval de valori decent de apropiat ca celelalte stații meteo din zonă, stația meteo va apărea și în WunderMap și va putea fi văzută de orice alt utilizator al serviciului. WunderMap poate fi consultată în varianta web sau în varianta de mobil (la fel și prognozele meteorologice furnizate de Weather Underground).

5

Norul udă ghivecele cu flori

Chiar dacă un sistem automat de menținere a umidității pentru ghivecelor cu flori rezolvă problema ”am uitat să ud florile” nu rezolvă și problema monitorizării exacte a umidității (necesare pentru diverse tipuri de plante mai pretențioase). Adăugarea unui sistem de jurnalizare a umidității permite vizualizarea și determinarea punctului de umiditate optimă pentru diverse astfel de tipuri de plante. În cadrul proiectului de față ne propunem să completăm sistemul prezentat în proiectul precedent (Arduino udă ghivecele cu flori) cu un sistem de monitorizare și comandă online. Pentru acest lucru vom utiliza serviciul online (de tip ”nor”) Adafruit IO. Serviciul Adafruit IO este un serviciu specializat IoT, gratuit, ce pune la dispoziția utilizatorilor atât posibilitatea jurnalizării valorilor preluate de la diverși senzori dar și transmiterea de comenzi către dispozitivele IoT și chiar legătura automată între partea de achiziție și comandă (reguli de conducere automată).

Pentru implementarea sistemului prezentat în această lecție este necesară crearea unui cont pe platforma Adafruit IO. După conectare trebuie să navigăm în meniul Settings și să ne notăm AIO Keys (cheia de autentificare) care va fi folosită, împreună cu denumirea contului creat, în programul sistemului.

Din punct de vedere hardware sistemul va avea în plus un modul Adafruit HUZZAH ESP8266 ce va asigura conectivitatea de rețea necesară accesării serviciului cloud.

2Astfel componentele necesare implementării sistemului sunt: Arduino Uno, shield drivere de motoare L298, senzor umiditate sol, pompă de apă micro, ecran LCD grafic Nokia (opțional) și modul Adafruit HUZZAH ESP8266. Alimentarea sistemului se va face de la un alimentator de rețea de 9V conectat la placa de dezvoltare Arduino Uno. Alimentatorul va alimenta atât componentele de comandă (placă de dezvoltare, modul WiFi, ecran LCD, senzor de umiditate sol) cât și pompa de apă (prin intermediul shield-ului L298 ce trebuie să aibă jumperul de alimentare comună conectat).

Conexiunile între componentele sistemului sunt următoarele:

  • Pompa de apă se conectează la shield-ul L298 pe canalul MOTOR2:

3

  • Senzorul de umiditate sol va utiliza pinul A0 pentru a transmite valoarea achiziționată către placa de dezvoltare, pinul A2 pentru alimentare și un pin de GND.

4

  • Ecranul LCD va utiliza următorii pini pentru conectare: LED – 5V (prin intermediul unei rezistențe de 220ohm), SCLK – D13, D/C – D8, RST – D7, SCE – A3 (nu mai putem folosi pinul D4 ca în cazul lecției precedente deoarece acest pin va fi utilizat de modul WiFi), GND – GND, Vcc – 3.3V.
  • Modulul WiFi Adafruit HUZZAH ESP8266 se va monta în soclul shield-ului L298 (soclu gândit pentru modul bluetooth dar compatibil și cu modulul WiFi utilizat de noi) – ATENȚIE la polaritate – conectați pinul de GND al modului la pinul de GND al soclului.

5

Înainte de asamblarea sistemului modulul WiFi trebuie programat separat de programarea plăcii Arduino Uno. Pentru programare este necesară utilizarea unui cablu USB to TTL sau a unui conector FTDI. Pentru programarea și utilizarea modulului Adafruit HUZZAH este recomandată parcurgerea materialului următor: Adafruit HUZZAH ESP8266 breakout .

Programul pentru modulul WiFi are rolul de a transforma comunicația serială (de la placa Arduino Uno) în mesaje MQTT pentru platforma Adafruit IO. Programul a fost dezvoltat și testat cu Arduino IDE 1.8.1 având instalată extensia ESP8266 Community 2.3.0 și utilizează biblioteca Adafruit MQTT 0.17.0. În program trebuie personalizate datele de conectare la rețeaua WiFi locală (WLAN_SSID și WLAN_PASS) precum și datele de conectare la serviciul cloud Adafruit IO (AIO_USERNAME și AIO_KEY).

#include <ESP8266WiFi.h>

#include “Adafruit_MQTT.h”

#include “Adafruit_MQTT_Client.h”

#define WLAN_SSID       “

#define WLAN_PASS       “

#define AIO_SERVER      “io.adafruit.com”

#define AIO_SERVERPORT  1883

#define AIO_USERNAME    “

#define AIO_KEY         “

WiFiClient client;

Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_USERNAME, AIO_KEY);

Adafruit_MQTT_Publish soilhumidity = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME “/feeds/soilhumidity”);

Adafruit_MQTT_Subscribe onoffbutton = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME “/feeds/onoff”);

void onoffcallback(char *data, uint16_t len) {

  String onoff_state = String(data);

  if (onoff_state==”ON”) Serial.println(“1”);

  else if (onoff_state==”OFF”) Serial.println(“0”);

}

void setup() {

  Serial.begin(115200);

  delay(10);

  Serial.println(F(“Adafruit MQTT NOR”));

  WiFi.begin(WLAN_SSID, WLAN_PASS);

  while (WiFi.status() != WL_CONNECTED) {

    delay(500);  }

  onoffbutton.setCallback(onoffcallback);

  mqtt.subscribe(&onoffbutton);

}

uint32_t x;

void loop() {

  MQTT_connect();

  mqtt.processPackets(100);

  if(Serial.available()){

    x=Serial.parseInt();

    soilhumidity.publish(x);

    }

  if(! mqtt.ping()) {

    mqtt.disconnect();

  }

}

void MQTT_connect() {

  int8_t ret;

  if (mqtt.connected()) {

    return;

  }

  uint8_t retries = 3;

  while ((ret = mqtt.connect()) != 0) {

        mqtt.disconnect();

       delay(10000);

       retries–;

       if (retries == 0) { while (1); }

  }

}

Programul pentru placa de dezvoltare Arduino Uno nu diferă foarte mult de varianta prezentată în proiectul precedent. Este necesară modificarea declarării obiectului LCD:

Adafruit_PCD8544 display = Adafruit_PCD8544(8, A3, 7);

declararea și configurarea comunicației seriale cu modulul WiFi:

#include “SoftwareSerial.h”

SoftwareSerial mySerial(2,4);

void setup()

{

  mySerial.begin(115200);

și de câteva completări în secțiunea loop():

void loop()

  int command = 0;

  int soilhumidity;

  digitalWrite(SOIL_VCC,LOW);

  mySerial.println(soilhumidity);

  display.println(millis()/1000);

  if(mySerial.available()){

    command = mySerial.parseInt();

  }

  if ((soilhumidity<500)||(command==1)) {

Programul ce rulează pe placa Arduino raportează serial către modulul WiFi valoarea umidității solului iar acesta raportează mai departe către serviciul cloud prin intermediul canalului soilhumidity. După prima execuție acest canal va apărea automat în interfața Adafruit IO.

6

În plus, sistemul va permite și comanda de la distanță a procesului de udare. Pentru acest lucru este nevoie să creăm manul în interfața Adafruit IO un canal denumit onoff. Acest canal va transmite către modulul WiFi comenzi de tipul ON / OFF, acestea vor fi retransmise către placa Arduino Uno ca și comenzi seriale de tip 1 / 0 și vor permite pornirea procesului de udare independent de valoarea umidității solului.

Pentru a putea transmite comenzile din interfața Adafruit IO putem crea o nouă consolă de comandă în secțiunea Dashboards. În această consolă de comandă putem plasa graficul de evoluție (Line Chart) a parametrului măsurat (umiditate sol) și un buton (Toggle) pentru comanda de udare.

7

În acest moment avem un sistem complet de urmărire și control la distanță a sistemului de udare – interfața web a serviciului Adafruit IO se poate accesa de oriunde de pe Internet.

Bineînțeles, sistemul propus poate fi îmbunătățit prin adăugarea mai multor parametrii de supravegheat (putem adăuga senzori de temperatură și umiditate a aerului, senzori de intensitate a luminii solare) completând astfel procesul de urmărire și control. Mai mult decât atât, serviciul Adafruit IO permite definirea de alarme de urmărire (avertizarea prin email când un parametru urmărit atinge un anume prag) sau chiar definirea de acțiuni asupra elementelor de comandă (putem implementa pragul de declanșare a procesului de udare la nivel de serviciu cloud).

Pentru mai multe detalii legate de funcționarea serviciului Adafruit IO puteți vedea și următoarele proiecte:

Monitor temperature & humidity from anywhere!

ESP8266 Power Meter Measure the DC power consumption of your devices!

Remote Control with the Huzzah + Adafruit.io

Log Light Levels to Adafruit IO

Track Your Treats: Halloween Candy GPS Tracker

Proiect Cloud’s Lights

Controlul iluminatului dintr-o locuință sau chiar dintr-o incintă mai mare prin intermediul serviciilor de cloud a devenit o soluție întâlnită din ce în ce mai des în aplicațiile de tip Home Automation sau Building Automation. Problema majoră a dispozitivelor ce permit acest tip de control este prețul foarte mare. Fie că alegem dispozitive conectate direct la Internet (becuri WiFi) fie că alegem soluții bazate pe controlere specializate de tip routere IoT, costul dispozitivelor necesare face ca aceste soluții să nu fie larg accesibile. În cadrul proiectului de față vom încerca să oferim o soluție fiabilă și accesibilă la problema controlului iluminatului într-o locuință prin intermediul rețelei Internet utilizând un serviciu de cloud.

Pentru controlul elementelor de iluminare vom utiliza dispozitive comutator pentru becuri din seria Conrad RSL comercializate în România de German Electronics SRL:

 

2

 

Avantajul acestor dispozitive este faptul că elementul de iluminare este separat, pot fi folosite cu orice tip de bec cu soclu E27 (max. 100W) și în momentul în care becul se arde nu trebuie să schimbăm și elementul de comandă (situație des întâlnită la becurile WiFi). Aceste dispozitive permit comanda radio de la distanță în bandă ISM de 433MHz – distanță de comandă de până la 25m (suficientă pentru majoritatea apartamentelor). Comanda se poate efectua cu orice telecomandă din seria Conrad RSL dar pe lângă telecomandă se pot folosi și comutatoare de perete din seria Conrad RSL:

3

Comutatoarele de perete funcționează pe baza unei baterii de 12V (tip 27A) făcându-le absolut independente de poziționarea rețelei de alimentare cu energie electrică – se pot aplica pe perete oriunde fără a avea nevoie de doză de conectare. Comutatoarele suplinesc telecomenzile permițând comanda a unui sau a două comutatoare de becuri (poziție închis/deschis).

Comutatorul de alimentare a becurilor necesită înregistrarea elementelor de comandă radio (telecomandă, comutator de perete). Butonul prezent la baza soclului poate fi utilizat pentru comanda manuală a becului dar și pentru înregistrarea codurilor de comandă (apăsare prelungă). Pentru operarea corectă a comutatorului este necesară citirea cu atenție a manualului furnizat de producător. Chiar dacă instalarea comutatorului de becuri este asemănătoare cu schimbul unui bec trebuie ca instalarea să se facă cu maximă grijă deoarece există pericol de electrocutare (opriți alimentarea cu energie electrică înainte de instalare!!!).

Pentru a putea reproduce comanda radio a unui astfel de comutator este necesară realizarea unui montaj simplu bazat pe o placă de dezvoltare Arduino Uno sau echivalentă și un receptor radio 433MHz.

 

4

 

Rulând exemplul ReceiveDemo_Simple al bibliotecii software rc-switch vom putea vizualiza tipul de cod și codul emis la fiecare apăsare de buton al comutatorului (sau telecomenzii):

5

https://github.com/sui77/rc-switch/

 

Codurile obținute (emise de comutator) se vor copia pentru a fi utilizate în program. Sistemul de comandă va fi format dintr-o placă de dezvoltare Adafruit Feather HUZZAH și un emițător radio 433MHz:

6

 

Emițătorul radio funcționează la o tensiune de 5V și din acest motiv este alimentat de la pinul USB (tensiunea furnizată de conexiunea USB a plăcii) – sistemul nu va funcționa corect dacă placa de dezvoltare este alimentată de la un acumulator. Pinul de date al emițătorului se va conecta la pinul 0 al plăcii de dezvoltare. Pentru mai multe informații despre instalarea și utilizarea plăcii Adafruit Feather HUZZAH puteți consulta:

Overview | Adafruit Feather HUZZAH ESP8266 | Adafruit Learning System

https://learn.adafruit.com/adafruit-feather-huzzah-esp8266/

Programul sistemului va utiliza mediul de dezvoltare Arduino IDE 1.8.1 și bibliotecile software: rc-switch 2.6.2, PubSubClient 2.6.0 (pentru comunicația MQTT cu serviciul de cloud), ArduinJson 5.8.3 (pentru interpretarea mesajelor provenite de la serviciul de cloud) și ESP8266WiFi 1.0.0.

#include <RCSwitch.h>

RCSwitch mySwitch = RCSwitch();

#include <ESP8266WiFi.h>

#include <PubSubClient.h>

#include <ArduinoJson.h>

Atenție!!! În cadrul bibliotecii PubSubClient este necesară modificarea fișierului PubSubClient.h: constanta MQTT_MAX_PACKET_SIZE trebuie schimbată din 128 în 256.

Pentru a permite conectarea la Internet este necesară personalizarea datelor de conectare la rețeaua WiFi locală (care să permită accesul la Internet):

const char* ssid     = “…”;

const char* password = “…”;

Constantele API_KEY, PROJECT_ID și DEVICE_UUID vor fi modificate conform proiectului înregistrat în serviciul de cloud (etapă explicată în secțiunea următoare).

#define API_KEY         “…”

#define PROJECT_ID      “…”

#define ACTUATOR_NAME1   “LightSocket1”

#define ACTUATOR_NAME2   “LightSocket2”

#define ACTUATOR_NAME3   “LightSocket3”

#define ACTUATOR_NAME4   “AllLightSockets”

#define DEVICE_UUID     “…”

#define sec 1000

char clientId[]          = “Feather_HUZZAH”;

char actuatorTopic1[]     = “/a/”API_KEY”/p/”PROJECT_ID”/d/”DEVICE_UUID”/actuator/”ACTUATOR_NAME1″/state”;

char actuatorTopic2[]     = “/a/”API_KEY”/p/”PROJECT_ID”/d/”DEVICE_UUID”/actuator/”ACTUATOR_NAME2″/state”;

char actuatorTopic3[]     = “/a/”API_KEY”/p/”PROJECT_ID”/d/”DEVICE_UUID”/actuator

/”ACTUATOR_NAME3″/state”;

char actuatorTopic4[]     = “/a/”API_KEY”/p/”PROJECT_ID”/d/”DEVICE_UUID”/actuator

/”ACTUATOR_NAME4″/state”;

char server[]            = “mqtt.devicehub.net”;

char message_buffer[150];

WiFiClient apiClient;

 

Procedura callback este necesară în cadrul comunicației MQTT – ea preia mesajele venite de la serviciul de cloud și le transpune în comenzi radio destinate comutatoarelor de becuri.

 

void callback(char* topic, byte* payload,

unsigned int length)

{

  StaticJsonBuffer<200> jsonBuffer;

  for(int i=0; i<length; i++)

  { message_buffer[i] = payload[i]; }

  JsonObject& root =

                 jsonBuffer.parseObject(message_buffer);

  if (!root.success()) {

    Serial.println(“parseObject() failed”);

    return;

  }

  boolean onoff = root[“state”];

  if(String(topic) == String(actuatorTopic1)){

      Serial.println(“message arrived: ” + String(onoff) + ” from Light Switch 1″);

      if (onoff) mySwitch.send(2189781504,32);

      else if (!onoff) mySwitch.send(2323999232,32);

  }else if ((String(topic) == String(actuatorTopic2))){

      Serial.println(“message arrived: ” + String(onoff) + ” from Light Switch 2″);

      if (onoff) mySwitch.send(2424662528,32);

      else if (!onoff) mySwitch.send(2558880256,32);

  }else if ((String(topic) == String(actuatorTopic3))){

      Serial.println(“message arrived: ” + String(onoff) + ” from Light Switch 3″);

      if (onoff) mySwitch.send(2625989120,32);

      else if (!onoff) mySwitch.send(2458216960,32);

  }else if ((String(topic) == String(actuatorTopic4))){

      Serial.println(“message arrived: ” + String(onoff) + ” from All Light Switch”);

      if (onoff) mySwitch.send(2474994176,32);

      else if (!onoff) mySwitch.send(2743429632,32);

  }

}

PubSubClient client(server, 1883, callback, apiClient);

 

În cadrul secțiunii setup() se va inițializa conexiunea WiFi și conexiunea MQTT cu serverul de cloud.

 

void setup() {

  Serial.begin(9600);

  delay(10);

  Serial.println();

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

  Serial.println(“\nStarting connection to server…”);

  if(client.connect(clientId)) 

  {

    client.subscribe(actuatorTopic1);

    client.subscribe(actuatorTopic2);

    client.subscribe(actuatorTopic3);

    client.subscribe(actuatorTopic4);

    Serial.println(“Successfuly connected and running!”);

  }

  else 

  {

    Serial.println(“Connection problem”);

  }

  mySwitch.enableTransmit(0);

  mySwitch.setProtocol(2);

  mySwitch.setRepeatTransmit(3);

  delay(500);

}

 

Secțiunea loop() are sarcina de a supraveghea conexiunea MQTT și de a o reface în cazul unei deconectări – prelucrarea mesajelor de comandă se face în procedura callback.

 

void loop() {

  if (!client.connected())

  { Serial.println(“reconnecting …”);

    client.connect(clientId);

    delay(3*sec);

    client.subscribe(actuatorTopic1);

    client.subscribe(actuatorTopic2);

    client.subscribe(actuatorTopic3);

    client.subscribe(actuatorTopic4);

  }

    client.loop();

}

Ca și serviciu de comandă cloud vom utiliza Devicehub.net – un serviciu de cloud specializat IoT care permite înregistrare gratuită a unui cont de dezvoltator (cont cu facilități suficiente pentru proiectul de față: 100 de dispozitive IoT, 100 de senzori . elemente de acționare, 10 mesaje/secundă, 30 milioane de mesaje/lună).

7

 

După înregistrarea contului se va genera un nou proiect denumit CloudLights (numele se poate modifica). În cadrul acestui proiect se vor adăuga 4 elemente de acționare digitale (Actuator / Digital) pe care le vom numi: LightSocket1, LightSocket2, LightSocket3, AllLightSockets (modificarea acestor denumiri necesită modificarea valorii constantelor ACTUATOR_NAME din program).  Acum se pot personaliza datele de conectare din program preluând cele necesare din secțiunea Development Information.

8

La execuție programul va avea următoarea raportare pe portul serial (fiecare comandă de închidere / deschidere se va materializa într-un mesaj provenit de la serverul de cloud):

9

La fiecare nouă conectare serviciul de cloud va realiza o inițializare cu starea memorată a comenzilor dar, având în vedere caracterul unidirecțional al comunicației radio, starea comenzilor din serviciul cloud nu oferă certitudinea unei anumite stări pentru comutatoare (starea acestora poate să fie modificată manual sau cu ajutorul unei telecomenzi).

Având în vedere diversitatea de dispozitive telecomandate din familia Conrad RSL aplicația de comandă se poate extinde incluzând și alte dispozitive: prize telecomandate, întrerupătoarea de perete sau comutatoare încastrabile:

10

Comutatoarele încastrabile pot fi instalate în doze de derivație și pot servi pentru a controla alimentarea cu energie a unor secțiuni din rețeaua electrică (o anexă din gospodărie de exemplu) dar instalarea lor necesită pregătire de specialitate – nu efectuați modificări ale instalației electrice singuri, apelați la un electrician!!!

 

În cazul în care doriți să dezvoltați sistemul propus puteți parcurge și următoarele proiecte asemănătoare:

 

ESP8266 Remote Controlled Sockets

http://randomnerdtutorials.com/esp8266-remote-controlled-sockets/

 

Switch a cheep 433Mhz RC-Socket  by an Adfafruit HUZZAH ESP8266 WebServer

http://fritzing.org/projects/esp8266-433mhz-rc-socket-switch

 

Using an ESP8266 to Control Mains Sockets Using 433mhz Transmitter and Receiver

http://www.instructables.com/id/Using-an-ESP8266-to-Control-Mains-Sockets-Using-43

Proiect WiFi Car Revolutions (partea a II-a)

Recunoașterea limbajului natural a devenit încet, încet o funcție obișnuită prin care putem comanda diverse dispozitive inteligente precum telefonul mobil sau calculatorul de bord al automobilul personal. Este posibil să implementăm o funcționalitate asemănătoare pentru WiFi Car? Este posibil să revoluționăm telecomenzile RC uzuale și să adăugăm comandă prin limbaj natural? Da!

2

Pentru a face acest lucru vom exploata conexiunea de rețea, prezentată în prima parte, pentru a conecta WiFi Car la un serviciu cloud de recunoaștere vocală. Puterea de calcul a plăcii de dezvoltare nu permite implementarea algoritmului de recunoaștere vocală local, pe placa de dezvoltare a WiFi Car, din această cauză vom apela la resursele de calcul a unui sistem de cloud. Sistemul de cloud utilizat este IBM BlueMixTM, serviciu cloud comercial dar cu posibilitatea de evaluare gratuită de 30 de zile fără a fi nevoie să introducem informații legate de un card bancar. Mai mult decât atât, în anumite centre universitare din țară accesul studenților și profesorilor este gratuit nelimitat. Pentru familiarizarea cu serviciul de cloud IBM BlueMixTM se poate revedea și lecția How sunny is the Blue? (I, II). Înregistrarea pe platformă se face la adresa:

Sign up for IBM Bluemix

https://console.ng.bluemix.net/registration/

După înregistrare și conectare la platformă se va naviga în zona de aplicații și se va crea o aplicație nouă (Create Application) de tipul Boilerplates / Internet of Things Platform Starter:

3

Se va alege un nume pentru aplicație (în cadrul lecției se va utiliza numele WCR dar puteți alege orice alt nume) și se va da comanda (Create) de alocare de resurse cloud pentru această aplicație nouă. Alocarea de resurse poate dura câteva minute sau zeci de minute. Finalizarea operației este marcată de schimbarea stării aplicației în Running.

4

În plus, trebuie să adăugm aplicației noastre un serviciu de tip Speech to Text (serviciul de recunoaștere vocală): Services /  Watson / Speech to Text. Noul serviciu trebuie asociat cu aplicația creată anterior (Conections / Create connection):

5

După definirea conexiunii aplicația WCR se va restarta. Pentru a putea conecta WiFi Car la aplicația nou creată trebuie să mergem în Dashboard-ul de administrare a serviciului WCR-iotf-service (Connect your devices / Launch dashboard). Comanda ne va direcționa către portalul IBM Watson IoT Platform unde vom crea un nou dispozitiv (Devices / Add Device). Nu trebuie să completăm decât tipul dipozitivului (în exemplul nostru Adafruit_HUZZAH) și numele dispozitivului (în exemplul nostru WCR). La finalizarea adăugării noului dispozitiv trebuie să notăm informațiile de autentificare furnizate de platformă pentru a putea să le folosim în programul dispozitivului (Organization ID, Device Type, Device ID, Authentication Method și Authentication Token).

6

Următorul pas este scrierea aplicație Node-RED care va face conversia între comenzile vocale date de utilizator și comenzile WiFi Car. Vom naviga la adresa https://wcr.mybluemix.net/ (adresa diferă în funcție de numele ales al aplicației) și vom accesa Node-RED flow editor (editorul vizual ce ne va permite scrierea aplicației). Aplicația are diagrama următoarea:

7

Pentru a putea utiliza elementul de intrare de tip microfon trebuie să instalăm următoarele două extensii Node-RED: node-red-contrib-browser-utils și node-red-contrib-media-utils (extensiile se instalează accesând din meniul principal opțiunea Manage palette). Elementul de intrare de tip microphone va permite înregistrea comenzilor vocale direct din browser și le va transmite automat către serviciul de recunoaștere vocală Speach to Text. Ieșirea serviciului de recunoaștere vocală se va conecta la un bloc decizional cu următoarea configurație:

8

Rolul blocului decizional este de a identifica comenzile vocale transcrise de serviciul de recunoaștere vocală (forward, backward, stop, left, right). Din păcate serviciul de recunoaștere vocală nu este disponibil în limba română. Ieșirile blocului decizional conduc la blocuri distincte de construire a comenzii în format JSON către serviciul IoT:

9

Serviciul IoT care va trimite, prin intermediul serviciului IBM Watson, comenzile către WiFi Car va avea următoarea configurație:

10

Pentru siguranță am adăugat un bloc de intrare pentru comanda de STOP care permite comanda manuală pentru cazuri de urgență. Restul componentelor din aplicație sunt utile doar pentru depanare: blocul msg.transcription va afișa textul de ieșire al serviciului de recunoaștere vocală iar blocurile WCR + msg.payload ne arată mesajele ce ajung efectiv la serviciul IoT.

Ultimul pas al implementării este reprogramarea modulului Adafruit HUZZAH pentru a prelua comenzile de la serviciul IBM Watson (pentru reprogramare modulul trebuie deconectat de la placa Arduino Uno). Programul a fost dezvoltat și testat utilizând Arduino IDE 1.8.1 și extensia esp8266 2.3.0 precum și bibliotecile MQTT 1.11.0 și ArduinoJson 5.8.3.

#include <ESP8266WiFi.h>

#include <MQTTClient.h>

#include <ArduinoJson.h>

 

Programul trebuie particularizat cu datele de conectare la rețeaua WiFi locală (ssid și password) precum și cu datele de autentificare la serviciul de cloud (OrgID, DeviceT, DeviceID, AuthenticationToken și OrgID):

const char* ssid     =  ““;

const char* password =  ““;

WiFiClient net;

MQTTClient client;

void connect_mqtt() {

while (!client.connect(“d:OrgID:DeviceT:DeviceID“, “use-token-auth”,”AuthenticationToken“)) {

delay(1000);

}

client.subscribe(“iot-2/cmd/+/fmt/json”);

}

void setup() {

Serial.begin(9600);

delay(10);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {

delay(500); }

client.begin(“OrgID.messaging.internetofthings. ibmcloud.com”, 1883, net);

connect_mqtt();

}

void loop() {

client.loop();

delay(10);

if (!client.connected()) { connect_mqtt(); }

}

void messageReceived(String topic, String payload, char * bytes, unsigned int length) {

StaticJsonBuffer jsonBuffer;

JsonObject& root = jsonBuffer.parseObject(payload);

if (!root.success()) {

return;

}

String command = root[“command”];

Serial.println(command);

}

Programul de pe placa Arduino Uno rămâne neschimbat. După reconectarea modulului Adafruit HUZZAH la WiFi Car putem să testăm comanda vocală. Din aplicația Node-RED se apasă butonul blocului microphone și se dă comanda (se înregistrează o comandă vocală care să conțină unul dintre cuvintele cheie forward, backward, stop, left sau right). Atenție, trebuie să permitem la nivel de browser ca aplicația Node-RED să acceseze dispozitivul hardware microfon al sistemului de calcul. După rostirea comenzii se apasă din nou butonul blocului microphone pentru a opri înregistrarea și a trimite comanda vocală către serviciul de recunoaștere vocală.

11

În captura de ecran anterioară se pot vedea mesajele din consola debug pentru o comandă vocală (right) și o comandă manuală (stop). Pentru comanda vocală se poate vedea atât recunoașterea vocală a comenzii cât și mesajul obținut ca feedback de la serviciul IoT. Pentru comanda manuală avem doar feedback-ul afișat.

Bineînțeles, ca alternativă la comanda vocală din browser există posibilitatea construirii unui sistem portabil de înregistrare vocală (telecomandă vocală). Proiectul de mai jos explorează această posibilitate utilizând o placă de dezvoltare Raspberry Pi:

Control your Robosapien Humanoid Robot using IBM Watson IoT Platform, Raspberry Pi and Node-RED (Part 1)

https://developer.ibm.com/recipes/tutorials/control-your-robosapien-humanoid-robot-using-ibm-watson-iot-platform-raspberry-pi-and-nodered/

Control the Humanoid Robot with voice commands using IBM Watson Speech to Text service (Part 2)

https://developer.ibm.com/recipes/tutorials/control-the-humanoid-robot-with-voice-commands-using-ibm-watson-speech-to-text-service-part-2/

Proiect WiFi Car Revolutions (partea I)

La fel ca și în cazul filmelor de succes, reluarea repetată a unei idei este destul de periculoasă din cauza epuizării rând pe rând a variantelor interesante ce pot capta atenția. Totuși, în cadrul proiectului de față vom relua problematica realizării unei platforme robotice comandate prin WiFi sperând să vă păstrăm în continuarea atenția și interesul prin propunerea unei soluții ”revoluționare” atât ca și componente hardware utilizate cât și ca modalitate de comandă.

Platforma robotică propusă se bazează pe aceiași platformă FlexyBot utilizată și în precedentele două WiFi Car (WiFi Car și WiFi Car Reloaded). Se poate utiliza atât varianta cu două motoare cât și varianta cu patru motoare (comandă unificată pentru motoarele de pe aceiași parte a platformei).

2

Pentru implementarea comenzii vom utiliza o soluție clasică: placă de dezvoltare Arduino Uno R3 și shield driver de motoare L298 (shield utilizat și în prima versiune a WiFi Car). Pentru a realiza conexiunea WiFi vom utiliza o componentă Adafruit HUZZAH ESP8266 ce permite o conversie între comunicația de rețea WiFi și comunicația serială.

3

Noua soluție de implementare a comenzii are următoarele avantaje:

  • Un cost mai mic (placa de dezvoltare Arduino Uno + modulul Adafruit HUZZAH sunt mai ieftine împreună decât placa de dezvoltare Arduino Yun);
  • Se poate implementa o alimentare comună, placa de dezvoltare se poate alimenta direct prin intermediul shield-ului de motoare – se poate utiliza o singură sursă de alimentare de 7.4V (accumulator LiPo cu două celule) sau 9V (cutie 6 baterii AA) direct pe pinii de alimentare a shieldului cu jumperul de alimentare pus;

4

  • Soluția este extrem de familiară fiind similară cu soluția propusă de kit-ul FlexyBot Doua Motoare Controlat prin Bluetooth – doar se înlocuiește modulul bluetooth cu cel WiFi – conectorul este compatibil cu noul modul fiind vorba tot de comunicație serială. Aveți grijă să potriviți pinul de GND al modulului cu pinul de GND al conectorului de pe shield.

5

 

Înainte de montarea modulului WiFi pe shield el trebuie programat, după montare nu mai este posibilă programarea deoarece pinii de programare sunt utilizați pentru comunicația serială cu placa Arduino Uno.

Pentru programarea și utilizarea modulului Adafruit HUZZAH este necesată parcurgerea materialului următor:

Adafruit HUZZAH ESP8266 breakout

https://learn.adafruit.com/adafruit-huzzah-esp8266-breakout

Programul ce va rula pe modulul Adafruit este derivat din exemplul WiFiTelnetToSerial al extensiei esp8266 pentru Arduino IDE (codul a fost testat utilizând Arduino IDE 1.8.1 și extensia esp8266 2.3.0):

#include <ESP8266WiFi.h>

#define MAX_SRV_CLIENTS 1

const char* ssid = ““;

const char* password = ““;

WiFiServer server(23);

WiFiClient serverClients[MAX_SRV_CLIENTS];

void setup() {

  Serial.begin(9600);

  Serial.println();

  WiFi.begin(ssid, password);

  uint8_t i = 0;

  while (WiFi.status() != WL_CONNECTED && i++ < 20)

delay(500);

  if(i == 21){ while(1) delay(500); }

   server.setNoDelay(true); }

 

void loop() {

  uint8_t i;

  if (server.hasClient()){

    for(i = 0; i < MAX_SRV_CLIENTS; i++){

      if (!serverClients[i] ||

                      !serverClients[i].connected()){

        if(serverClients[i]) serverClients[i].stop();

        serverClients[i] = server.available();

        serverClients[i].println(F(“=== WiFi Car Revolutions ===”));

        continue;

      }

    }

    WiFiClient serverClient = server.available();

    serverClient.stop();

  }

  for(i = 0; i < MAX_SRV_CLIENTS; i++){

    if (serverClients[i] && serverClients[i].connected()){

      if(serverClients[i].available()){

        while(serverClients[i].available())

Serial.write(serverClients[i].read()); }

    }

  }

  if(Serial.available()){

    size_t len = Serial.available();

    uint8_t sbuf[len];

    Serial.readBytes(sbuf, len);

    for(i = 0; i < MAX_SRV_CLIENTS; i++){

      if (serverClients[i] &&

                      serverClients[i].connected()){

        serverClients[i].write(sbuf, len);

        delay(1);  }

    }

  }

}

Pentru încărcarea codului se va utiliza un cablu USB to TTL sau un conector FTDI. Modulul WiFi va încerca conectarea într-o rețea WiFi locală ce oferă IP-ul dinamic prin DHCP – credențialele de conectare (ssid și password) trebuie personalizate în program.

După programarea modulului WiFi el poate fi conectat la platforma mobilă și se poate trece la programarea plăcii Arduino Uno. Codul pentru componenta Arduino este similar cu codul utilizat în cadrul variantei WiFi Car Reloaded pentru componenta 32U4 – programul va avea rolul de a transpune comenzile primite serial în comenzi către motoare (apar deosebiri la pinii de comandă ai motoarelor și la portul serial folosit, în cazul de față vom utiliza un port serial software – toate specifice shield-ului de motoare folosit).

#define MOTOR2_PIN1 3

#define MOTOR2_PIN2 5

#define MOTOR1_PIN1 6

#define MOTOR1_PIN2 9

#include “SoftwareSerial.h”

SoftwareSerial mySerial(2,4);

int vs = 0;

int vd = 0;

void setup()

{ mySerial.begin(9600);

  pinMode(MOTOR1_PIN1, OUTPUT);

  pinMode(MOTOR1_PIN2, OUTPUT);

  pinMode(MOTOR2_PIN1, OUTPUT);

  pinMode(MOTOR2_PIN2, OUTPUT); }

 

void loop()

{ if (mySerial.available()) {

    char c = (char)mySerial.read();

    switch (c) {

      case ‘i’:

        if (vs<245) vs=vs+10;

        if (vd<245) vd=vd+10;

        mySerial.print(“Viteza: “);

        mySerial.print(vs);

        mySerial.print(“/”);

        mySerial.println(vd);

        break;

      case ‘b’:

        if (vs>-245) vs=vs-10;

        if (vd>-245) vd=vd-10;

        mySerial.print(“Viteza: “);

        mySerial.print(vs);

        mySerial.print(“/”);

        mySerial.println(vd);

        break;

      case ‘s’:

        if (vs<245) vs=vs+10;

        if (vd>-245) vd=vd-10;

        mySerial.print(“Viteza: “);

        mySerial.print(vs);

        mySerial.print(“/”);

        mySerial.println(vd);

        break;

      case ‘d’:

        if (vs>-245) vs=vs-10;

        if (vd<245) vd=vd+10;

        mySerial.print(“Viteza: “);

        mySerial.print(vs);

        mySerial.print(“/”);

        mySerial.println(vd);

        break;       

      case ‘x’:

        vs=0;

        vd=0;

        mySerial.print(“Viteza: “);

        mySerial.print(vs);

        mySerial.print(“/”);

        mySerial.println(vd);

        break;

    }

  }

  mySerial.flush();

  go(vs,vd);

  delay(50);

}

 

void go(int speedLeft, int speedRight) {

  if (speedLeft > 0) {

    analogWrite(MOTOR1_PIN1, speedLeft);

    analogWrite(MOTOR1_PIN2, 0);

  }

  else {

    analogWrite(MOTOR1_PIN1, 0);

    analogWrite(MOTOR1_PIN2, -speedLeft);

  }

  if (speedRight > 0) {

    analogWrite(MOTOR2_PIN1, speedRight);

    analogWrite(MOTOR2_PIN2, 0);

  }else {

    analogWrite(MOTOR2_PIN1, 0);

    analogWrite(MOTOR2_PIN2, -speedRight);

  }

}

Comanda platformei robotice rezultate se poate face, la fel ca și în cazul WiFi Car Reloaded,  utilizând un client telnet (adresa de conectare este adresa IP alocată modulului WiFi prin DHCP) și comenzile i, d, s, b, x:

6

Sau utilizând aplicația Android RoboRemoFree – Arduino control:

7

https://play.google.com/store/apps/details?id=com.hardcodedjoy.roboremofree

și configurând o interfață cu cinci butoane pentru comenzile i, d, s, b, x.

8

Adresa de conectare va fi adresa IP a sistemului și portul va fi portul 23 (specific protocolului telnet):

9