Go Down

Topic: Presentazione di ThermoWeb - Domotica IP - c/php/js/sql (Read 12138 times) previous topic - next topic

andrea86

Ciao a tutti, tramite Arduino ho fatto questo cronotermostato completamente configurabile via internet tramite pagine web oppure applicazioni android/ios. Attualmente il sistema si appoggia su un web server su cui gira apache e mysql.







L' utente, dopo essersi autenticato, può visualizzare le varie località a lui connesse e scegliere per ogni luogo la temperatura desiderata e la modalità di funzionamento ( spento / manuale / automatica ). Nella modalità automatica è possibile la programmazione di ogni ora per ogni giorno della settimana.

Sempre da remoto è possibile impostare l' orologio di sistema, la temperatura minima e massima e anche quanti gradi di isteresi da rispettare.

Per ora vengono usati arduino uno con ethernet shield + uno shield disegnato da me che ospita il DS1307 + batteria tampone e cristallo ( l' orologio di sistema ), il DS1624 ( sensore di temperatura ) e un 2N7000 ( un mosfet usato come stadio di potenza e ho aggiunto anche un condensatore da 100nF tra gate e gnd per evitare sfarfallamenti del relè ). Il relè, per questioni di sicurezza, ho preferito installarlo nel quadro elettrico ed è un Finder serie 34. Larghi solo 5mm si comandano a 5 Vdc e sono in grado di gestire 6A a 250 Vac. Inoltre nello zoccolo del relè è integrato il circuito di protezione oltre a quello di segnalamento.

Nel mio progetto ogni nodo arduino è indipendente e necessita solo dell' alimentazione locale ( fornita dal cavo ethernet ) per funzionare. Ad ogni accensione del micro vengono richiamati dalla memoria le ultime impostazione volute dall' utente. L' ora di sistema è fornita solo dal DS1307, però l' utente quando si collega è informato se tra l' ora dell' arduino e quella del web server c' è una differenza maggiore di 60 secondi. La comunicazione tra il web server e un nodo arduino è tramite richieste REST e le risposte sono in JSON. Attualmente ho implementato 8 richieste ( quelle con numerazioni dispari sono comandi per variare i parametri, mentre quelle pari informano sullo stato dei parametri ). Per ogni richiesta di variazione è prevista anche una richiesta di informazione sul parametro appena variato. Se la richiesta non è specificata, il micro risponde informando della temperatura ambiente / impostata / minima / massima e la modalità di funzionamento ( oltre ad indicare lo stato dell' uscita relè ).

Ad esempio una richiesta del tipo:
Code: [Select]
http://192.168.1.232/?76121
serve a programmare il cronotermostato che di Domenica dalle 12.00 alle 13.00 deve essere acceso il riscaldamento e genera la risposta:
Code: [Select]
[0,0,0,0,0,0,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
mentre una richiesta senza specifiche:
Code: [Select]
http://192.168.1.232
ha come risposta:
Code: [Select]
{"temp":24.06,"tSet":24,"tMin":15,"tMax":25,"mode":2,"info":0}

leo72

Complimenti bella cosa davvero.
Però perché il tuo progetto possa restare qui devi fornire tutti i sorgenti e gli schemi del lavoro nonché la documentazione, altrimenti va spostato in "Software".

Michele Menniti


Complimenti bella cosa davvero.
Però perché il tuo progetto possa restare qui devi fornire tutti i sorgenti e gli schemi del lavoro nonché la documentazione, altrimenti va spostato in "Software".

Concordo con Leo. Andrea, mi associo ai complimenti ma ci siamo sempre dati la regola che questa sezione va usata come "condivisione" dei propri lavori, in modo che tutti possano usufruirne, così com'è tu stai facendo solo "vetrina". Comunque ti basta riaprire il Topic in Software e poi eliminare questo con il pulsante posto in basso a sinistra nella pagina "remove topic". Grazie. :)
Guida alla programmazione ISP e seriale dei micro ATMEL (Caricare bootloader e sketch):
http://www.michelemenniti.it/Arduino_burn_bootloader.php
Guida alla Programmazione ATmega328 noP:
http://www.michelemenniti.it/atmega328nop.html
Articoli su Elettronica In:
http://www.michelemenniti.it/elettronica_in.html

andrea86

Ho aperto la discussione qui perchè credevo che era per i progetti funzionanti e non per richieste  :smiley-red:

Questo è il codice per arduino, non pensavo di pubblicarlo e quindi non è il massimo da leggere...

Quote

#include <Wire.h>
#include <SPI.h>
#include <Ethernet.h>
#include <EEPROM.h>

#define pinRele 14
#define defMode 1
#define defTMin 15
#define defTMax 25
#define defIsteresi 2
#define defCrono 1;

byte time[7], crono[168], mode, tMin, tMax, tSet, isteresi, info;
byte mac[]     = { 0x90, 0xA2, 0xDA, 0x00, 0xFF, 0x41 };
byte ip[]      = { 192, 168, 1, 232 };
byte gateway[] = { 192, 168, 1, 254 };
byte subnet[]  = { 255, 255, 255, 0 };
byte id[]      = { 1, 2, 3, 4 };
float temp;

EthernetServer server(80);

void setup()
{
  Ethernet.begin(mac, ip, gateway, subnet);
  server.begin();
  
  Wire.begin();
  
  // temperatura
  
  Wire.beginTransmission(0x48);
    Wire.write(0xAC);
    Wire.write(0x00);
  Wire.endTransmission();
  
  delay(100);
  
  Wire.beginTransmission(0x48);
    Wire.write(0xEE);
  Wire.endTransmission();
  
  // fine temperatura
  
  pinMode (pinRele, OUTPUT);
  
  mode = EEPROM.read(0);

  if (mode < 0 || mode > 2)
  {
    mode = defMode;
    EEPROM.write(0, mode);
  }

  tMin = EEPROM.read(1);

  if (tMin < 10 || tMin > 20)
  {
    tMin = defTMin;
    EEPROM.write(1, tMin);
  }

  tMax = EEPROM.read(2);

  if (tMax < 20 || tMax > 30)
  {
    tMax = defTMax;
    EEPROM.write(2, tMax);
  }

  tSet = EEPROM.read(3);

  if (tSet < tMin || tSet > tMax)
  {
    tSet = tMin;
    EEPROM.write(3, tSet);
  }

  isteresi = EEPROM.read(4);

  if (isteresi < 0 || isteresi > 3)
  {
    isteresi = defIsteresi;
    EEPROM.write(4, isteresi);
  }

  for (byte x1 = 0; x1 < 168; x1++)
  {
    crono[x1] = EEPROM.read(x1 + 5);
    
    if (crono[x1] < 0 || crono[x1] > 1)
    {
      crono[x1] = defCrono;
      EEPROM.write(x1 + 5, crono[x1]);
    }
  }
}

void loop()
{
  check();

  EthernetClient client = server.available();
  
  if (client)
  {
    boolean currentLineIsBlank = true;
    byte get[18] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    int x1 = 0;
    
    while (client.connected())
    {
      
      if (client.available())
      {
        char c = client.read();
        
        if (x1 > 5 && x1 < 24)
        {          
          get[x1 - 6] = c & 15;
        }  
        
        x1++;
        
        if (c == '\n' && currentLineIsBlank)
        {
        
          if (get[0] == id[0] && get[1] == id[1] && get[2] == id[2] && get[3] == id[3])
          {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html");
            client.println("Connnection: close");
            client.println();
            
            switch (get[4])
            {                       
              case 3 : if (get[5] == 1)
                       {
                         x1 = get[6] * 10 + get[7];
                         
                         if (x1 >= 10 && x1 <= 20)
                         {
                           tMin = x1;
                           EEPROM.write(1, tMin);
                         }
                       }
                       
                       if (get[8] == 1)
                       {
                         x1 = get[9] * 10 + get[10];
                         
                         if (x1 >= 20 && x1 <= 30)
                         {
                           tMax = x1; 
                           EEPROM.write(2, tMax);
                         }
                       }
                       
                       if (get[11] == 1)
                       {
                         
                         if (get[12] >= 0 && get[12] <= 3)
                         {
                           isteresi = get[12];
                           EEPROM.write(4, isteresi);
                         }
                       }
              
              case 4 : client.print("{\"id\":");
                       client.print(id[0]);
                       client.print(id[1]);
                       client.print(id[2]);
                       client.print(id[3]);
                       client.print(",\"tMin\":");
                       client.print(tMin);
                       client.print(",\"tMax\":");
                       client.print(tMax);
                       client.print(",\"isteresi\":");
                       client.print(isteresi);
                       client.println("}");
                       break;
              
              case 5 : time[0] = get[9] * 16 + get[10];
                       time[1] = get[7] * 16 + get[8];
                       time[2] = get[5] * 16 + get[6];
                       time[3] = get[11];
                       time[4] = get[12] * 16 + get[13];
                       time[5] = get[14] * 16 + get[15];
                       time[6] = get[16] * 16 + get[17];

andrea86

seconda parte ( tagliato in due per pubblicarlo )

Quote

                       Wire.beginTransmission(0x68);
                       
                       Wire.write(0x00);
                       for (byte x2 = 0; x2 < 7; x2++)
                       {
                         Wire.write(time[x2]);
                       }
                       Wire.endTransmission();
                       
              case 6 : getTime();
                       client.print("{\"ore\":");
                       client.print(time[2], HEX);
                       client.print(",\"minuti\":");
                       client.print(time[1], HEX);
                       client.print(",\"secondi\":");
                       client.print(time[0], HEX);
                       client.print(",\"gSettimana\":");
                       client.print(time[3], HEX);
                       client.print(",\"gMese\":");
                       client.print(time[4], HEX);
                       client.print(",\"mese\":");
                       client.print(time[5], HEX);
                       client.print(",\"anno\":");
                       client.print(time[6], HEX);
                       client.println("}");
                       break;
              
              case 7 : if (get[8] >= 0 && get[8] <= 1)
                       {
                         x1 = get[5] * 24 + (get[6] * 10 + get[7]);
                         crono[x1] = get[8];
                         EEPROM.write(x1 + 5, crono[x1]);
                       }
                       
              case 8 : client.print("[");
                       for (byte x2 = 0; x2 < 167; x2++)
                       {
                         client.print(crono[x2]);
                         client.print(",");
                       }
                       client.print(crono[167]);
                       client.println("]");
                       break;
                       
              case 9 : if (get[5] == 1)
                       {
                         if (get[6] >= 0 && get[6] <= 2)
                         {
                           mode = get[6];
                           EEPROM.write(0, mode);
                         }
                       }
                       
                       if (get[7] == 1)
                       {
                         x1 = get[8] * 10 + get[9];
                         
                         if (x1 >= tMin && x1 <= tMax)
                         {
                           tSet = x1;
                           EEPROM.write(3, tSet);
                         }
                       }

              default : check();
              
                        client.print("{\"temp\":");
                        client.print(temp);
                        client.print(",\"tSet\":");
                        client.print(tSet);
                        client.print(",\"tMin\":");
                        client.print(tMin);
                        client.print(",\"tMax\":");
                        client.print(tMax);
                        client.print(",\"mode\":");
                        client.print(mode);
                        client.print(",\"info\":");
                        client.print(info);
                        client.print("}");
            }
          }  
              
          break;
        }
        
        if (c == '\n')
        {
          currentLineIsBlank = true;
        }
        
        else if (c != '\r')
        {
          currentLineIsBlank = false;
        }
      }
    }
    delay(1);
    client.stop();
  }
}

void getTemp()
{
  byte msByte;
  byte lsByte;
  
  Wire.beginTransmission(0x48);
    Wire.write(0xAA);
  Wire.endTransmission();
  
  Wire.requestFrom(0x48, 2);  
    if (Wire.available())
    {  
      lsByte = Wire.read();
    }  
    if (Wire.available())
    {
      msByte = Wire.read();
    }  
  temp = float(lsByte) + float(msByte >> 3) * 0.03125;
}

void getTime()
{
  
  Wire.beginTransmission(0x68);
  Wire.write(0x00);
  Wire.endTransmission();
  
  Wire.requestFrom(0x68, 7);
  
  for (byte x1 = 0; x1 < 7; x1++)
  { 
    if (Wire.available())
    {
      time[x1] = Wire.read();
    }
  }
}

void check()
{
  getTemp();
  
  switch(mode)
  {
    case 0 : digitalWrite(pinRele, LOW);
             info = 0;
             break;
             
    case 1 : if (temp < float(tSet))
             {
               digitalWrite(pinRele, HIGH);
               info = 1;
             }
             
             else if (temp >= float(tSet + isteresi))
             {
               digitalWrite(pinRele, LOW);
               info = 0;
             }
             
             break;
             
    case 2 : getTime();
             byte x1 = (time[3] - 1) * 24 + ((time[2] >> 4) * 10) + (time[2] & 15);
              
             if (crono[x1] != 0 && temp < float(tSet))
             {
               digitalWrite(pinRele, HIGH);
               info = 1;
             }
             
             else if (crono[x1] == 0 || temp >= float(tSet + isteresi))
             {
               digitalWrite(pinRele, LOW);
               info = 0;
             }
  }
}

andrea86

Ci aggiungo anche la pagina in .php che contiene la parte ajax per la visualizzazione dinamica dei parametri:

Code: [Select]
<?php

session_start();

if (!isset($_SESSION['id'])) {

header('location:session_expired.php');
exit;

}

else

$userId $_SESSION['id'];

$dbHostname "";
$dbUsername "";
$dbPassword "";
$dbDatabase "";

$con mysql_connect($dbHostname$dbUsername$dbPassword);

if (!$con)

die("Unable to connect to MySQL: " mysql_error());

mysql_select_db($dbDatabase$con) or die("Unable to select database: " mysql_error());

$sql "SELECT host.addr, host.proto, host.rqst, host.desc FROM host, rela WHERE rela.userId = " $userId " AND rela.hostId = host.id";

$result mysql_query($sql);

if (!$result)

die("Database access failed: " mysql_error());

$numRows mysql_num_rows($result);

mysql_free_result($result);

if (empty($_GET['place']))

$place 0;

else

$place $_GET['place'];

$sql "SELECT host.id, host.addr, host.proto, host.rqst, host.desc FROM host, rela WHERE rela.userId = " $userId " AND rela.hostId = host.id LIMIT " $place ", 1";

$result mysql_query($sql);

if (!$result)

die("Database access failed: " mysql_error());

$obj mysql_fetch_object($result);

mysql_free_result($result);

mysql_close($con);

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="user-scalable=no, width=device-width, minimum-scale=1.0, maximum-scale=1.0" />
<title>ThermoWeb 1.0</title>
<link href="css/default.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">

var url = "get.php?addr=<?php echo $obj->addr?>&proto=<?php echo $obj->proto?>&rqst=<?php echo $obj->rqst?>";
var set;

function ajaxRequest() {

var xmlhttp = new XMLHttpRequest();

xmlhttp.onreadystatechange = function() {

if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {

var json=eval("("+xmlhttp.responseText+")");

document.getElementById("temp").innerHTML = Math.round(json.temp * 10) / 10 + "&deg;C";
document.getElementById("tSet").innerHTML = json.tSet;

switch (json.mode) {

case 0: document.getElementById("offOff").style.visibility = "hidden";
document.getElementById("onOff").style.visibility = "visible";
document.getElementById("autoOff").style.visibility = "visible"; break;

case 1: document.getElementById("offOff").style.visibility = "visible";
document.getElementById("onOff").style.visibility = "hidden";
document.getElementById("autoOff").style.visibility = "visible"; break;

case 2: document.getElementById("offOff").style.visibility = "visible";
document.getElementById("onOff").style.visibility = "visible";
document.getElementById("autoOff").style.visibility = "hidden";

}

switch (json.info) {

case 0: document.getElementById("info").innerHTML = "St-By"; break;

case 1: document.getElementById("info").innerHTML = "Run";

}

set = json.tSet;

if (set <= json.tMin) {

document.getElementById("mOn").style.visibility = "hidden";

}

else {

document.getElementById("mOn").style.visibility = "visible";

}

if (set >= json.tMax) {

document.getElementById("pOn").style.visibility = "hidden";

}

else {

document.getElementById("pOn").style.visibility = "visible";

}

}

}
 
xmlhttp.open("GET", url, true);

xmlhttp.send();

}

function setMode(val) {

var oldUrl = url;
url = url + "91" + val + "000";

ajaxRequest();

url = oldUrl;

}

function setTemp(val) {

var oldUrl = url;

if (val == 0)

set--;

if (val == 1)

set++;

url = url + "9001" + set;

ajaxRequest();

url = oldUrl;

}

window.onLoad = ajaxRequest();
setInterval(ajaxRequest, 1000);

</script>
</head>
<body>
<div class="container">
<h1><?php

        
if ($place != 0) {

echo '<a href="show.php?place=';
echo $place 1;
echo '">&lt;</a>';

}

else

echo '&lt;';

echo ' ' $obj->desc ' ';

if ($place $numRows) {

echo ' <a href="show.php?place=';
echo $place 1;
echo '">&gt;</a>';

}

else

echo '&gt;';

?>
</h1>
<div class="content">
<h1 id="temp">00.0&deg;C</h1>
<div class="barElements">
<h1>Set</h1>
<div id="mOff">
<a id="mOn" href="javascript:setTemp(0)"><img src="images/mOn.png" width="30" height="30" alt="-" /></a>
</div>
<h2 id="tSet">00</h2>
<div id="pOff">
<a id="pOn" href="javascript:setTemp(1)"><img src="images/pOn.png" width="30" height="30" alt="+" /></a>
</div>
</div>
<div class="barElements">
<h1>Mode</h1>
<div id="offOn">
<a id="offOff" href="javascript:setMode(0)"><img src="images/offOff.png" width="30" height="30" alt="Off" /></a>
</div>
<div id="onOn">
<a id="onOff" href="javascript:setMode(1)"><img src="images/onOff.png" width="30" height="30" alt="On" /></a>
</div>
<div id="autoOn">
<a id="autoOff" href="javascript:setMode(2)"><img src="images/autoOff.png" width="30" height="30" alt="Auto" /></a>
</div>
</div>
<div class="barElements">
<h1>Status</h1>
<h2 id="info">null</h2>
</div>
<div class="barElements">
<h1>Preferences</h1>
<div class="ico">
<a href="crono.php?hostId=<?php echo $obj->id?>"><img src="images/crono.png" width="30" height="30" alt="Crono" /></a>
</div>
<div class="ico">
<a href="#"><img src="images/pref.png" width="30" height="30" alt="Preferences" /></a>
</div>
</div>
</div>
<div class="footer">
<p>&copy; ThermoWeb <?php echo date("Y"); ?> | <a href="#">help</a> |</p>
</div>
</div>
</body>
</html>

andrea86

E lo script in .php più importante, serve come proxy per aggirare le limitazioni del ajax:

Code: [Select]
<?php

echo 
file_get_contents("http://".$_GET['addr'].":".$_GET['proto']."/?".$_GET['rqst']);

?>

Michele Menniti

Andrea, NON devi giustificarti, ti abbiamo spiegato una regola, ora tu hai completato la pubblicazione ed hai condiviso il tuo lavoro, non ti preoccupare della "bellezza", se qualcuno avrà dei dubbi ti chiederà, a questo serve aprire un Topic. Grazie!
Guida alla programmazione ISP e seriale dei micro ATMEL (Caricare bootloader e sketch):
http://www.michelemenniti.it/Arduino_burn_bootloader.php
Guida alla Programmazione ATmega328 noP:
http://www.michelemenniti.it/atmega328nop.html
Articoli su Elettronica In:
http://www.michelemenniti.it/elettronica_in.html


lesto

#9
Jan 07, 2013, 03:20 pm Last Edit: Jan 07, 2013, 03:50 pm by lesto Reason: 1
bel lavoro!

edit: non capisco bene il sistema che usi per comunicare i tempi di accensione (non ho visto il codice ma solo la stringa di risposta)

Se hai la precisione di un'ora e devi solo indicare acceso/spento, allora ti serve un array di 24 byte (1 byte per ora, dove i bit rappresentano i giorni: il bit 0 è il lunedì, il bit 1 il martedì, etc... e ti avanza pure un bit!) invece usi un array di 128 e non capisco il perchè
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

leo72


1 byte per ora, dove i bit rappresentano i giorni: il bit 0 è il lunedì, il bit 1 il martedì, etc... e ti avanza pure un bit!

Per le festività  :smiley-yell:

leo72


Andrea, NON devi giustificarti, ti abbiamo spiegato una regola, ora tu hai completato la pubblicazione ed hai condiviso il tuo lavoro, non ti preoccupare della "bellezza", se qualcuno avrà dei dubbi ti chiederà, a questo serve aprire un Topic. Grazie!

E sono ben felice anch'io della condivisione.

E ti do pure un suggerimento. Raccogli tutto dentro ad un unico archivio compresso così faciliti il download a chi volesse scaricare il tuo lavoro per replicarlo o prendere spunti.

andrea86

#12
Jan 07, 2013, 10:06 pm Last Edit: Jan 07, 2013, 10:09 pm by andrea86 Reason: 1

bel lavoro!

edit: non capisco bene il sistema che usi per comunicare i tempi di accensione (non ho visto il codice ma solo la stringa di risposta)

Se hai la precisione di un'ora e devi solo indicare acceso/spento, allora ti serve un array di 24 byte (1 byte per ora, dove i bit rappresentano i giorni: il bit 0 è il lunedì, il bit 1 il martedì, etc... e ti avanza pure un bit!) invece usi un array di 128 e non capisco il perchè


Ciao, se ho capito bene la tua domanda è come fa arduino a capire quale ora di quale giorno deve accendere il riscaldamento?

Lo script proxy in .php invia ad arduino "http://192.168.1.232:80/?123476121", dove 1234 è un controllo che ho aggiunto, non fa sicurezza ma evita risposte ad una richiesta che ha ricevuto erroneamente. Scusa nel primo post non c'era.
Il micro elimina già i primi 5 caratteri che sono GET/? e incomincia dal 6° a convertire i caratteri che seguono. Per la conversione sfrutto il fatto che in ASCII i caratteri numerici da 0 a 9 sono il valore BCD preceduto da "0011" e quindi uso il comando "c & 15" per mascherare i primi 4 bit dal MSB. Puoi anche usare int(c) e sottrarre 48 in decimale.

Per la gestione oraria/giornaliera uso un array da 168 elementi di tipo byte ( 24 ore x 7 giorni ) ed effettivamente spreco 7 bit per elemento. Però risparmio in cicli macchina o almeno credo! :D

lesto

bhe sicuramente risparmi in mal di testa :)

però tolto 1234 ti rimane 76121, sono 5 numeri mentre ci sono 7 giorni... cosa mi sfugge?

Quote
Puoi anche usare int(c) e sottrarre 48 in decimale.


char e byte sono la stessa cosa, puoi fare c-48 senza fare cast, al massimo ti becchi un warning :)
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

andrea86


bhe sicuramente risparmi in mal di testa :)

però tolto 1234 ti rimane 76121, sono 5 numeri mentre ci sono 7 giorni... cosa mi sfugge?

Quote
Puoi anche usare int(c) e sottrarre 48 in decimale.


char e byte sono la stessa cosa, puoi fare c-48 senza fare cast, al massimo ti becchi un warning :)


7 è per il case dello switchcase

6 è per il giorno della settimana dove lunedì = 0, martedì = 1 ecc fino a domenica = 6

1 e 2 sono decine e unità ricomposte e corrispondo alla fascia oraria 12.00 - 12.59

1 è acceso ( se 0 spento )

Go Up