Differenze
Queste sono le differenze tra la revisione selezionata e la versione attuale della pagina.
| Entrambe le parti precedenti la revisioneRevisione precedenteProssima revisione | Revisione precedente | ||
| metern [2023/07/25 09:43] – [prova] walter | metern [2023/07/30 17:08] (versione attuale) – walter | ||
|---|---|---|---|
| Linea 99: | Linea 99: | ||
| Le comapps sono dei programmi, in qualsiasi linguaggio, che servono per interrogare un dispositivo di misura e leggerne i dati. | Le comapps sono dei programmi, in qualsiasi linguaggio, che servono per interrogare un dispositivo di misura e leggerne i dati. | ||
| - | Per poterlo fare bisogna innanzitutto che il dispositivo abbia apposite API per poterlo interrogare, | + | Per come realizzare e configurare correttamente le comapps |
| - | MeterN ha già delle comapss preconfezionate realizzate e messe a disposizione dall' | + | ===== ===== |
| - | + | ||
| - | ===== Comapss standard ===== | + | |
| - | + | ||
| - | * pool123s Se avete installato e funzionante 123solar questa comapss si intefaccia con l' | + | |
| - | * remotepool123s come il precedente ma legge i dati su un sito remoto dove è installato 123solar | + | |
| - | * houseenergy E' una comapps che legge vari meter, imposta vari Meter Id (i meter id sono fissi in quanto servono per calcolare i dati) | + | |
| - | + | ||
| - | ===== Comapss autoprodotte ===== | + | |
| - | + | ||
| - | Le comapps sono di due tipi, alla fine fanno le stesse cose, ma le fanno in modo diverso: | + | |
| - | + | ||
| - | * pooler = leggono continuamente i dati direttamente dal meter (un dato alla volta) | + | |
| - | * Daemon = sono dei programmi che leggono tutti i dati dal meter li parcheggiano su un file di supporto da dove vengono letti mediante un pooler | + | |
| - | + | ||
| - | per capire la differenza di funzionamento facciamo un esempio comparativo, | + | |
| - | Con un pooler si devono fare 4 cicli di lettura sul meter (tipicamente un SDM o uno Shelly) \\ | + | |
| - | Con un Daemon si fa un solo ciclo di lettura sul meter e poi si legge 4 volte il file di supporto. | + | |
| - | + | ||
| - | Il primo è da preferire se si leggono uno o due dati, il secondo è molto più performante se si devono leggere molti dati inoltre è molto utile nei casi in cui si debbano leggere dati da siti web dove ci sono limiti al numero di letture orarie e/o giornaliere | + | |
| - | + | ||
| - | ===== Struttura delle comapps ===== | + | |
| - | + | ||
| - | <wrap em> | + | |
| - | + | ||
| - | Sono file singoli che vengono attivati direttamente da MeterN e si interfacciano direttamente col meter | + | |
| - | + | ||
| - | ^Programma^Descrizione^Esempio| | + | |
| - | |pooler.php|programma che legge i dati dal meter e li passa a MeterN|shelly1.php| | + | |
| - | + | ||
| - | <wrap em> | + | |
| - | + | ||
| - | qui la cosa si fa più strutturata, | + | |
| - | + | ||
| - | ^Programma^Descrizione^Esempio| | + | |
| - | |com_daemon.php|Avvia il daemon_loop|shelly0_daemon.php| | + | |
| - | |daemon_loop.php|legge i dati dal meter|shelly0_loop.php| | + | |
| - | |daemon.php|pooler che legge i dati dal file di supporto|shelly0.php| | + | |
| - | + | ||
| - | Ogni pooler o daemon dovrà avere tanti parametri quanti sono i dati che gestisce per poter richiamare il dato necessario al momento, questo parametro verrà richiamato da MeterN e sarà inserito nella configurazione dei vari meter | + | |
| - | + | ||
| - | ====== Creare una comapps ====== | + | |
| - | + | ||
| - | ===== Comapps pooler ===== | + | |
| - | + | ||
| - | Dobbiamo posizionare il programma nella directory che conterrà tutte le comapps, ma lo dobbiamo fare come amministratore, | + | |
| - | procedere nel seguente modo: | + | |
| - | + | ||
| - | < | + | |
| - | sudo -s | + | |
| - | cd / | + | |
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | Con il nostro edito preferito creiamo il file: | + | |
| - | + | ||
| - | < | + | |
| - | poolshelly.php | + | |
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | Al suo interno andremo a inserire il seguente codice: | + | |
| - | + | ||
| - | <code php [enable_line_numbers=" | + | |
| - | + | ||
| - | # | + | |
| - | <?php | + | |
| - | + | ||
| - | if (isset($_SERVER[' | + | |
| - | die(' | + | |
| - | } | + | |
| - | + | ||
| - | error_reporting(~E_WARNING); | + | |
| - | + | ||
| - | // This script will output a ShellyEM counter into a meterN compatible format | + | |
| - | // Configure, then ln -s / | + | |
| - | // Request Main command with ' | + | |
| - | + | ||
| - | // Shelly IP | + | |
| - | $IP = ' | + | |
| - | // Shelly request | + | |
| - | $url = " | + | |
| - | $remotedata = file_get_contents($url); | + | |
| - | + | ||
| - | // meterN config | + | |
| - | + | ||
| - | $METERID | + | |
| - | + | ||
| - | // No edit is needed below | + | |
| - | + | ||
| - | if (isset($argv[1])) { | + | |
| - | + | ||
| - | $GP = null; | + | |
| - | if (!empty($remotedata)) { | + | |
| - | $memarray = json_decode($remotedata, | + | |
| - | if ($argv[1] == ' | + | |
| - | $GP = $memarray[' | + | |
| - | $GP = round($GP, 1); | + | |
| - | echo " | + | |
| - | } | + | |
| - | elseif ($argv[1] == ' | + | |
| - | if (isset($memarray[' | + | |
| - | $KWHT = round($memarray[' | + | |
| - | echo " | + | |
| - | } else { | + | |
| - | die(" | + | |
| - | } | + | |
| - | } | + | |
| - | elseif ($argv[1] == ' | + | |
| - | $GP = $memarray[' | + | |
| - | $GP = round($GP, 1); | + | |
| - | echo " | + | |
| - | } | + | |
| - | elseif ($argv[1] == ' | + | |
| - | if (isset($memarray[' | + | |
| - | $KWHT = round($memarray[' | + | |
| - | echo " | + | |
| - | } else { | + | |
| - | die(" | + | |
| - | } | + | |
| - | } | + | |
| - | } else { | + | |
| - | die(" | + | |
| - | } | + | |
| - | } else { | + | |
| - | die(" | + | |
| - | } | + | |
| - | ?> | + | |
| - | + | ||
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | dobbiamo inoltre rendere il file eseguibile dal sistema, per far questo eseguiamo i seguenti passaggi: | + | |
| - | < | + | |
| - | + | ||
| - | cd / | + | |
| - | chown www-data: | + | |
| - | chmod a+x / | + | |
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | a questo punto dobbiamo creare un link simbolico per poter richiamare il programma | + | |
| - | + | ||
| - | < | + | |
| - | ln -s / | + | |
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | ora siamo pronti per l' | + | |
| - | + | ||
| - | Dalla shell, con riga di comando lanciare tutte le opzioni previste nel software per assicurarsi che diano il risultato voluto, se avete previsto la gestione degli errori, generateli, per assicurarvi che il software li gestisca correttamente, | + | |
| - | + | ||
| - | < | + | |
| - | poolshelly energy | + | |
| - | poolshelly energy1 | + | |
| - | poolshelly power | + | |
| - | poolshelly power1 | + | |
| - | poolshelly | + | |
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | l' | + | |
| - | + | ||
| - | Quando tutto funziona possiamo abilitare il programma in MeterN, per far ciò dobbiamo modificare un file di sistema (sistema di MeterN) in questo modo: | + | |
| - | + | ||
| - | < | + | |
| - | cd / | + | |
| - | nano allowed_comapps.php | + | |
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | alle voci esistenti aggiungere altre voci all' | + | |
| - | + | ||
| - | < | + | |
| - | $ALLWDCMD[n] = ' | + | |
| - | $ALLWDCMD[n] = ' | + | |
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | la struttura è la seguente: | + | |
| - | + | ||
| - | - [//n//] = il numero tra parentesi quadre deve essere un numero progressivo che segue quelle già presenti | + | |
| - | - poolshelly = link simbolico che richiama il nostro programma | + | |
| - | - energy = opzione da richiamare | + | |
| - | + | ||
| - | inserire tante voci quante sono le opzioni che vi serve richiamare | + | |
| - | + | ||
| - | + | ||
| - | ===== Comapps daemon ===== | + | |
| - | + | ||
| - | Come detto in precedenza dobbiamo creare 3 programmi, per tenere in ordine i programmi, se non già fatto, creeremo una directory dove posizionare i com_daemon che in effetti non servono a manipolare i dati ma ad avviare i daemon_loop. | + | |
| - | + | ||
| - | < | + | |
| - | sudo -s | + | |
| - | cd / | + | |
| - | mkdir -v daemon | + | |
| - | + | ||
| - | </ | + | |
| - | ==== Daemon_loop ==== | + | |
| - | + | ||
| - | Iniziamo ora a creare il programma di loop che andrà a leggere il nostro meter nello specifico si tratta di uno Shelly EM con una sola pinza che legge immissioni e prelievi distinguendoli con i valori positivi per i prelievi e negativi per le immissioni, il file lo chiameremo shelly_3_loop.php | + | |
| - | + | ||
| - | <code php [enable_line_numbers=" | + | |
| - | + | ||
| - | # | + | |
| - | <?php | + | |
| - | if (isset($_SERVER[' | + | |
| - | die(' | + | |
| - | } | + | |
| - | // Beware, only use a tmpfs as /dev/shm (ramfs) ! | + | |
| - | + | ||
| - | // This script will perform a loop to continuosly | + | |
| - | // Request the follow data {energy | power | volt | ampere | cosphi | energy1 | power1 }' | + | |
| - | // **** Measurements performed with a single clamp that measures import + ed export - ****** | + | |
| - | // by Walter62 | + | |
| - | + | ||
| - | $IP = ' | + | |
| - | $CH = 0; // Channel "0 = import" | + | |
| - | $MID = 3; // meterN config | + | |
| - | + | ||
| - | // No edit is needed below | + | |
| - | + | ||
| - | $url = " | + | |
| - | $filelog = " | + | |
| - | + | ||
| - | while (true) { | + | |
| - | $dataarray = array(); | + | |
| - | $remotedata = ""; | + | |
| - | + | ||
| - | $remotedata = file_get_contents($url); | + | |
| - | // | + | |
| - | + | ||
| - | if (!empty($remotedata)) { | + | |
| - | $memarray = json_decode($remotedata, | + | |
| - | + | ||
| - | $GP = round($memarray[' | + | |
| - | + | ||
| - | if ($GP <0){ | + | |
| - | $GP_0 = 0; | + | |
| - | $GP_1 = abs($GP); | + | |
| - | } else { | + | |
| - | $GP_0 = $GP; | + | |
| - | $GP_1 = 0; | + | |
| - | } | + | |
| - | + | ||
| - | //channel 0 ==> Import | + | |
| - | // | + | |
| - | $KWHT_0 = round($memarray[' | + | |
| - | + | ||
| - | //Channel 1 ==> Export | + | |
| - | // | + | |
| - | //$KWHT_1 = round($memarray[' | + | |
| - | $KWHT_1 = round($memarray[' | + | |
| - | + | ||
| - | //channel $CH | + | |
| - | $VOLT = round($memarray[' | + | |
| - | $AMP = abs(round (${' | + | |
| - | $PHI = abs(round($memarray[' | + | |
| - | + | ||
| - | $dataarray[0] = $MID . ' | + | |
| - | $dataarray[1] = $MID . ' | + | |
| - | $dataarray[2] = $MID . ' | + | |
| - | $dataarray[3] = $MID . ' | + | |
| - | $dataarray[4] = $MID . ' | + | |
| - | $dataarray[5] = $MID . ' | + | |
| - | $dataarray[6] = $MID . ' | + | |
| - | $str = implode(PHP_EOL, | + | |
| - | file_put_contents('/ | + | |
| - | + | ||
| - | } else { | + | |
| - | if (file_exists($filelog)) { | + | |
| - | $now = time(); | + | |
| - | if ($now - filemtime($filelog)> | + | |
| - | unlink('/ | + | |
| - | } | + | |
| - | } | + | |
| - | } | + | |
| - | usleep(500000); | + | |
| - | } | + | |
| - | ?> | + | |
| - | + | ||
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | Dato che con una pinza leggo sia il valore di energia importata che esportata ma con valore negativo, ho disabilitato la lettura del canale e dalla riga 34 alla 40 vado a leggere il valore di energia letto dalla pinza e in funzione che sia positivo o negativo assegno al canale appropriato il valore assoluto quindi positivo per entrambi i canali. | + | |
| - | + | ||
| - | Ora che abbiamo il file compilato lo salviamo in: | + | |
| - | < | + | |
| - | + | ||
| - | / | + | |
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | + | ||
| - | ==== daemon ==== | + | |
| - | + | ||
| - | Ora passiamo alla stesura del programma che si occuperà di leggere i dati e renderli disponibili a MeterN, lo chiameremo shelly_3.php, | + | |
| - | + | ||
| - | <code php [enable_line_numbers=" | + | |
| - | + | ||
| - | # | + | |
| - | <?php | + | |
| - | if (isset($_SERVER[' | + | |
| - | die(' | + | |
| - | } | + | |
| - | // This script will read output file of the ShellyEM counter and will expos the data to MeterN | + | |
| - | // Configure, then ln -s / | + | |
| - | // Request Main command with ' | + | |
| - | // by Walter62 | + | |
| - | + | ||
| - | $MID = 3; // meter to call - shelly_n = shelly_3 | + | |
| - | $filelog = " | + | |
| - | + | ||
| - | // No edit is needed | + | |
| - | + | ||
| - | $help = " | + | |
| - | + | ||
| - | if (!isset($argv[1])) { | + | |
| - | die($help); | + | |
| - | } | + | |
| - | + | ||
| - | if ($argv[1] == ' | + | |
| - | $outstr = exec(' | + | |
| - | }elseif ($argv[1] == ' | + | |
| - | $outstr = exec(' | + | |
| - | }elseif ($argv[1] == ' | + | |
| - | $outstr = exec(' | + | |
| - | }elseif ($argv[1] == ' | + | |
| - | $outstr = exec(' | + | |
| - | }elseif ($argv[1] == ' | + | |
| - | $outstr = exec(' | + | |
| - | }elseif ($argv[1] == ' | + | |
| - | $outstr = exec(' | + | |
| - | }elseif ($argv[1] == ' | + | |
| - | $outstr = exec(' | + | |
| - | } else{ | + | |
| - | die($help); | + | |
| - | } | + | |
| - | + | ||
| - | echo " | + | |
| - | ?> | + | |
| - | + | ||
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | salviamo il file in: | + | |
| - | < | + | |
| - | + | ||
| - | / | + | |
| - | + | ||
| - | </ | + | |
| - | + | ||
| - | A questo punto abbiamo: | + | |
| - | + | ||
| - | * Il daemon che legge i dati dal file di supporto | + | |
| - | * Il daemon_loop che legge i file dal meter e li salva nel file di supporto | + | |
| - | + | ||
| - | Il primo lo fa partire MeterN a chiamata, ma il secondo deve partire ad ogni avvio di sistema, o meglio di MeterN e rimanere in esecuzione. \\ Potremmo inserire l' | + | |
| - | + | ||
| - | ==== daemon_com ==== | + | |
| - | + | ||
| - | Nel nostro caso, chiameremo il programma shelly_3_daemon.php e dovrà avere il seguente contenuto: | + | |
| - | + | ||
| - | + | ||
| - | <code php shelly_3_daemon.php> | + | |
| - | + | ||
| - | # | + | |
| - | <?php | + | |
| - | /* | + | |
| - | Check shelly_3_loop.php path bellow | + | |
| - | Then ln -s /path to/ | + | |
| - | Start and stop the daemon via metern/ | + | |
| - | And request values with shelly_3 command | + | |
| - | */ | + | |
| - | + | ||
| - | if (isset($_SERVER[' | + | |
| - | die(' | + | |
| - | } | + | |
| - | + | ||
| - | if (file_exists('/ | + | |
| - | $cdpid = (int) file_get_contents('/ | + | |
| - | exec(" | + | |
| - | if (!isset($ret[1])) { | + | |
| - | $cdpid = null; | + | |
| - | unlink('/ | + | |
| - | } | + | |
| - | } else { | + | |
| - | $cdpid = null; | + | |
| - | } | + | |
| - | + | ||
| - | if (isset($argv[1])) { | + | |
| - | if (($argv[1] == ' | + | |
| - | unlink('/ | + | |
| - | } | + | |
| - | if ($argv[1] == ' | + | |
| - | if (is_null($cdpid)) { | + | |
| - | $command = 'php / | + | |
| - | $cdpid | + | |
| - | file_put_contents('/ | + | |
| - | } else { | + | |
| - | echo " | + | |
| - | } | + | |
| - | } else if ($argv[1] == ' | + | |
| - | if (!is_null($cdpid)) { | + | |
| - | $command = exec(" | + | |
| - | unlink('/ | + | |
| - | } | + | |
| - | } else { | + | |
| - | echo "Usage : shelly_3_daemon {start | stop}\n"; | + | |
| - | } | + | |
| - | } else { | + | |
| - | echo "Usage : shelly_3_daemon {start | stop}\n"; | + | |
| - | } | + | |
| - | ?> | + | |
| - | </ | + | |
| - | + | ||
| - | + | ||
| - | ====== prova ====== | + | |
| - | + | ||
| - | <code php prova.php> | + | |
| - | sfbsfb | + | |
| - | FBFB | + | |
| - | FBFDB | + | |
| - | Bdbdfd | + | |
| - | $a=25 | + | |
| - | + | ||
| - | + | ||
| - | </ | + | |