[Script] Evaporation piscine sur Raspberry

Discussion et échanges de scripts pour la box eedomus

[Script] Evaporation piscine sur Raspberry

Messagepar Herbert » 25 Août 2018 17:11

Pour les passionnés, je livre tel quel un script à installer et exécuter sur Raspberry; j'ai pas mal galéré pour trouver les formules et les paramètres, alors si cela peut être utile à quelqu'un ...
L'objectif est de calculer l'évaporation de la piscine (par jour ou par heure) à partir des données suivantes : températures de l'air et de l'eau, humidité de l'air, vitesse du vent et pression atmosphérique. Ce résultat peut ensuite être utilisé pour faire un bilan du niveau de la piscine (à condition de mesurer ce niveau) et détecter d'éventuelles fuites.
Les données doivent aussi avoir préalablement été mesurées et stockées quelque part; j'utilise personnellement une base de données MySQL sur Raspberry, dont voici la structure:

    -- $ Mysql -p -u root
    -- Enter password: xxxxxx
    -- Base de données: `piscine`
    -- --------------------------------------------------------
    CREATE DATABASE IF NOT EXISTS piscine;
    -- CREATE DATABASE `piscine`;
    USE piscine;
    -- --------------------------------------------------------
    -- Structure de la table `Devices` (Piscine, Extérieur)
    --
    CREATE TABLE IF NOT EXISTS `Devices` (
    `dID` int(5) NOT NULL AUTO_INCREMENT,
    `Name` varchar(50) NOT NULL,
    PRIMARY KEY (`dID`),
    UNIQUE KEY `dID` (`dID`)
    );
    -- --------------------------------------------------------
    -- Structure de la table `Pool` (Température de l'eau)
    --
    CREATE TABLE IF NOT EXISTS `Pool` (
    `dID` tinyint(4) NOT NULL,
    `Name` varchar(50) NOT NULL,
    `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `measure_time` datetime NOT NULL,
    `value` decimal(10,1) NOT NULL,
    `unit` enum('L','W','Celsius','W/h','%','m/s','mb') NOT NULL
    );
    -- --------------------------------------------------------
    -- Structure de la table `Temp` (température de l'air)
    --
    CREATE TABLE IF NOT EXISTS `Temp` (
    `dID` tinyint(4) NOT NULL,
    `Name` varchar(50) NOT NULL,
    `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `measure_time` datetime NOT NULL,
    `value` decimal(10,1) NOT NULL,
    `unit` enum('L','W','Celsius','W/h','%','m/s','mb') NOT NULL
    );
    -- --------------------------------------------------------
    -- Structure de la table `Hum` (Humidité de l'air)
    --
    CREATE TABLE IF NOT EXISTS `Hum` (
    `dID` tinyint(4) NOT NULL,
    `Name` varchar(50) NOT NULL,
    `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `measure_time` datetime NOT NULL,
    `value` decimal(10,1) NOT NULL,
    `unit` enum('L','W','Celsius','W/h','%','m/s','mb') NOT NULL
    );
    -- --------------------------------------------------------
    -- Structure de la table `Wind` (Vitesse du vent)
    --
    CREATE TABLE IF NOT EXISTS `Wind` (
    `dID` tinyint(4) NOT NULL,
    `Name` varchar(50) NOT NULL,
    `measure_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `value` decimal(10,1) NOT NULL,
    `unit` enum('L','W','Celsius','W/h','%','m/s','mb') NOT NULL
    );
    -- --------------------------------------------------------
    -- Structure de la table `Atm` (Pression atmosphérique)
    --
    CREATE TABLE IF NOT EXISTS `Atm` (
    `dID` tinyint(4) NOT NULL,
    `Name` varchar(50) NOT NULL,
    `measure_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `value` decimal(10,1) NOT NULL,
    `unit` enum('L','W','Celsius','W/h','%','m/s','mb') NOT NULL
    );
    -- --------------------------------------------------------
    -- Structure de la vue `AvgTwByDay`
    --
    CREATE VIEW `AvgTwByDay` AS (select date_format(`Pool`.`update_time`,'%Y%m%d') AS `update_time`,
    `Pool`.`dID` AS `dID`,
    Avg(`Pool`.`value`) AS `AVG` from `Pool`
    Group by date_format(`Pool`.`update_time`,'%Y%m%d'),`Pool`.`dID`);
    -- --------------------------------------------------------
    -- Structure de la vue `AvgTrByDay`
    --
    CREATE VIEW `AvgTrByDay` AS (select date_format(`Temp`.`update_time`,'%Y%m%d') AS `update_time`,
    `Temp`.`dID` AS `dID`,
    Avg(`Temp`.`value`) AS `AVG` from `Temp`
    Group by date_format(`Temp`.`update_time`,'%Y%m%d'),`Temp`.`dID`);
    -- --------------------------------------------------------
    -- Structure de la vue `AvgHumByDay`
    --
    CREATE VIEW `AvgHumByDay` AS (select date_format(`Hum`.`update_time`,'%Y%m%d') AS `update_time`,
    `Hum`.`dID` AS `dID`,
    Avg(`Hum`.`value`) AS `AVG` from `Hum`
    Group by date_format(`Hum`.`update_time`,'%Y%m%d'),`Hum`.`dID`);
    -- --------------------------------------------------------
    -- Structure de la vue `AvgWindByDay`
    --
    CREATE VIEW `AvgWindByDay` AS (select date_format(`Wind`.`measure_time`,'%Y%m%d') AS `measure_time`,
    `Wind`.`dID` AS `dID`,
    Avg(`Wind`.`value`) AS `AVG` from `Wind`
    Group by date_format(`Wind`.`measure_time`,'%Y%m%d'),`Wind`.`dID`);
    -- --------------------------------------------------------
    -- Structure de la vue `AvgAtmByDay`
    --
    CREATE VIEW `AvgAtmByDay` AS (select date_format(`Atm`.`measure_time`,'%Y%m%d') AS `measure_time`,
    `Atm`.`dID` AS `dID`,
    Avg(`Atm`.`value`) AS `AVG` from `Atm`
    Group by date_format(`Atm`.`measure_time`,'%Y%m%d'),`Atm`.`dID`);
    -- --------------------------------------------------------
    -- Structure de la vue `AvgWindByHr`
    --
    CREATE VIEW `AvgWindByHr` AS (select date_format(`Wind`.`measure_time`,'%Y%m%d%H') AS `measure_time`,
    `Wind`.`dID` AS `dID`,
    Avg(`Wind`.`value`) AS `AVG` from `Wind`
    Group by date_format(`Wind`.`measure_time`,'%Y%m%d%H'),`Wind`.`dID`);
    -- --------------------------------------------------------
    -- Structure de la vue `AvgAtmByHr`
    --
    CREATE VIEW `AvgAtmByHr` AS (select date_format(`Atm`.`measure_time`,'%Y%m%d%H') AS `measure_time`,
    `Atm`.`dID` AS `dID`,
    Avg(`Atm`.`value`) AS `AVG` from `Atm`
    Group by date_format(`Atm`.`measure_time`,'%Y%m%d%H'),`Atm`.`dID`);
    -- --------------------------------------------------------
    -- Structure de la vue `AvgTwByHr`
    --
    CREATE VIEW `AvgTwByHr` AS (select date_format(`Pool`.`update_time`,'%Y%m%d%H') AS `update_time`,
    `Pool`.`dID` AS `dID`,
    Avg(`Pool`.`value`) AS `AVG` from `Pool`
    Group by date_format(`Pool`.`update_time`,'%Y%m%d%H'),`Pool`.`dID`);
    -- --------------------------------------------------------
    -- Structure de la vue `AvgTrByHr`
    --
    CREATE VIEW `AvgTrByHr` AS (select date_format(`Temp`.`update_time`,'%Y%m%d%H') AS `update_time`,
    `Temp`.`dID` AS `dID`,
    Avg(`Temp`.`value`) AS `AVG` from `Temp`
    Group by date_format(`Temp`.`update_time`,'%Y%m%d%H'),`Temp`.`dID`);
    -- --------------------------------------------------------
    -- Structure de la vue `AvgHumByHr`
    --
    CREATE VIEW `AvgHumByHr` AS (select date_format(`Hum`.`update_time`,'%Y%m%d%H') AS `update_time`,
    `Hum`.`dID` AS `dID`,
    Avg(`Hum`.`value`) AS `AVG` from `Hum`
    Group by date_format(`Hum`.`update_time`,'%Y%m%d%H'),`Hum`.`dID`);
    -- --------------------------------------------------------
Et voici le code php :
Code : Tout sélectionner
<?php
/**************************************************************************************/
/*         ### Calculs et écriture de l'évaporation piscine  ####                     */
/**************************************************************************************/
/*************************************** API eedomus **********************************/
//  Authentification : Toutes les requêtes doivent être associées à un utilisateur eedomus valide créé sur https://secure.eedomus.com
// L'authentification à l'API est différente de celle utilisée sur le portail eedomus. Sur le portail, un utilisateur est authentifié
// par son identifiant et mot de passe. Avec l'API eedomus l'authentification se fait avec un api_user et un api_secret qui peuvent être
// demandés et révoqués à tout moment en vous rendant sur la section Mon compte du portail eedomus.
// Pour des raisons de sécurité, api_user/api_secret sont envoyés uniquement par mail, pour les récupérer, rendez vous sur
// https://secure.eedomus.com, et allez dans Configuration / Mon compte / Paramètres et cliquez sur Identifiants pour l'API -> Envoyer
$api_user = 'xxxxxx' ; // A renseigner
$api_secret = 'xxxxxxxxxxxxxxx' ; // A renseigner
//*************************************** Paramètres network **************************/
//@IP eedomus
$IPeedomus = 'api.eedomus.com' ;
// Périphérique Eedomus à mettre à jour
$periph_id1 = 'xxxxxx' ; // code API Evaporation (J-1) - A renseigner

// ****************   Read variables from mysql db  ******************************
$port = 'xxxx' ; // A renseigner (par défaut : 3306)
$uid = 'xxxxxx' ; // A renseigner
$pwd = 'xxxxxxxx' ; // A renseigner

$db = mysql_connect('localhost:'.$port.', '.$uid.', '.$pwd.''); // MySQL database
mysql_select_db('database',$db) or die(mysql_error()) ; // Renseigner database

// Choix des vues
$tair = 'AvgTrByHr' ; // (ou bien : AvgTrByDay)
$teau = 'AvgTwByHr' ; // (ou bien : AvgTwByDay)
$hair = 'AvgHumByHr' ; // (ou bien : AvgHumByDay)
$vent = 'AvgWindByHr' ; // (ou bien : AvgWindByDay)
$pres = 'AvgAtmByHr' ; // (ou bien : AvgAtmByDay)

$sql1 = 'SELECT update_time FROM '.$tair.' ORDER BY update_time DESC LIMIT 1'; /*Current stats update time*/
$cur = mysql_query($sql1) or die('Erreur SQL !'.mysql_error()) ; /*H-1*/
$cur_date = mysql_fetch_array($cur, MYSQL_BOTH) ;
$current = $cur_date[0] ;

$sql2 = 'SELECT AVG FROM '.$tair.' WHERE update_time < '.$current.' ORDER BY update_time DESC LIMIT 1' ; /*H-1 air temperature average*/
$sql3 = 'SELECT AVG FROM '.$teau.' WHERE update_time < '.$current.' ORDER BY update_time DESC LIMIT 1' ; /*H-1 water temperature average*/
$sql4 = 'SELECT AVG FROM '.$hair.' WHERE update_time < '.$current.' ORDER BY update_time DESC LIMIT 1' ; /*H-1 air humidity average*/
$sql5 = 'SELECT AVG FROM '.$vent.' WHERE measure_time < '.$current.' ORDER BY measure_time DESC LIMIT 1' ; /*H-1 wind average (km/h)*/
$sql6 = 'SELECT AVG FROM '.$pres.' WHERE measure_time < '.$current.' ORDER BY measure_time DESC LIMIT 1' ; /*H-1 atmospheric pressure (mb)*/

$tempa = mysql_query($sql2) or die('Erreur SQL !'.mysql_error()) ; // D-1 air temperature average
$ta = mysql_fetch_array($tempa, MYSQL_BOTH) ;

$tempw = mysql_query($sql3) or die('Erreur SQL !'.mysql_error()) ; // D-1 water temperature average
$tw = mysql_fetch_array($tempw, MYSQL_BOTH) ;

$hum = mysql_query($sql4) or die('Erreur SQL !'.mysql_error()) ; // D-1 air humidity average
$a_hum = mysql_fetch_array($hum, MYSQL_BOTH) ;

$winda = mysql_query($sql5) or die('Erreur SQL !'.mysql_error()) ; // D-1 wind average (km/h)
$windk = mysql_fetch_array($winda, MYSQL_BOTH) ;
$wind = $windk[0] * 1000 / 3600 ; // En m/s

$atmp = mysql_query($sql6) or die('Erreur SQL !'.mysql_error()) ;  // D-1 atmospheric pressure (mb)
$atm = mysql_fetch_array($atmp, MYSQL_BOTH) ;

// *********************************   Constante  *****************************
$surf = xx.x ; // Surface de la piscine (m2) - A renseigner

// ****************************************************************************
//MEASUREMENT AND ANALYSIS OF EVAPORATION FROM AN INACTIVE OUTDOOR SWIMMING POOL
// CHARLES C. SMITH GEORGE LOF RANDY JONES (1994)
// m/A = ((30.6 + 32.1*Vw)*(Pe - Pr))/DeltaHv
$rose = dew_point($ta[0], $a_hum[0]) ; // Point de rosée à la température de l'air ambiant
$pr = vapor_sat($rose) ; // Pression de vapeur saturante au point de rosée de l'air ambiant (mmHg)
$pe = vapor_sat($tw[0]) ; // Pression de vapeur saturante à la température de l'eau (mmHg)
$delta_hv = latent_heat($tw[0]) ; // Chaleur latente à la température de l'eau : kJ/kg
$debit1 = ((30.6 + 32.1*$wind)*($pe - $pr))/$delta_hv ; // kg/hr*m2
$loss1 = $debit1*$surf*24 ; // Perte (kg = l) par jour
$level1 = $loss1/$surf ; // Baisse de niveau (mm)

// ****************************************************************************
// Methods for Calculation of Evaporation from Swimming Pools and Other Water Surfaces
// Mirza Mohammed Shah, PE, PhD (2014)
// http://mmshah.org/publications/ASHRAE%202014%20Evaporation%20paper.pdf (Shah)
// E0=(a*(u/b)^0.7)*(pw-pa) : Equation (7)
$psa = vapor_sat($ta[0])*133.322387415 ; // Pression de vapeur saturante aux conditions de l'air ambiant (Pa)
$pa = $a_hum[0]*$psa/100 ; // Partial pressure of water vapor in air away from the water surface (Pa)
$psw = vapor_sat($tw[0])*133.322387415 ; // Pression de vapeur saturante à la surface de l'eau (Pa)
$pw = $psw*100/100 ; // Partial pressure of water vapor in saturated air (Pa)
$debit2 = (0.00005*pow($wind/0.15,0.7))*($pw-$pa) ; // kg/hr*m2
$loss2 = $debit2*$surf*24 ; // Perte (kg = l) par jour
$level2 = $loss2/$surf ; // Baisse de niveau (mm)

// E0=C*Ro(w)*[[Ro(r)-Ro(w)]1/3]*[W(w)-W(r)] : Equation (1)
$Td_r = $rose ; // Point de rosée à la température de l'air ambiant
$Td_w = dew_point($tw[0], 100) ; // Point de rosée, saturé à la température de l'eau
$e_r = 6.112 * exp((17.67 * $Td_r) / ($Td_r + 243.5)) ; // Vapor pressure in mb at air dew point
$e_w = 6.112 * exp((17.67 * $Td_w) / ($Td_w + 243.5)) ; // Vapor pressure in mb at water dew point
$W_r = (0.622 * $e_r) / ($atm[0] - (0.378 * $e_r)) ; // Specific humidity of air at air temperature and humidity
$W_w = (0.622 * $e_w) / ($atm[0] - (0.378 * $e_w)) ; // Specific humidity of air saturated at water surface temperature

// Tables psychrometriques (reconstituées)
$a1 = 0.0683620431269243 ; // LN(Slope) of correlation specific volume vs RH at given temperature: slope
$b1 = -9.89810359802448 ; // LN(Slope) of correlation specific volume vs RH at given temperature: intercept
$ln_a_r = $ta[0]*$a1 + $b1 ; // LN(Correlation slope): specific volume vs RH
$a_r = exp($ln_a_r) ; // Correlation slope: specific volume vs RH
$a2 = 0.00285817163228928 ; // Intercept of correlation specific volume vs RH at given temperature: slope
$b2 = 0.785281996434938 ; // Intercept of correlation specific volume vs RH at given temperature: intercept
$b_r = $ta[0]*$a2 + $b2 ; // Correlation intercept: specific volume vs RH
$Ro_r = 1 / ($a_hum[0]*$a_r + $b_r) ; // Density of air = mass of dry air per unit volume of moist air, kg/m3 (at air temperature and humidity)
                                      // This is the density in psychrometric charts and tables
$a3 = 0.00416195569136746 ; // Specific volume vs temperature (saturated) : slope
$b3 = 0.783106951871658 ; // Specific volume vs temperature (saturated) : intercept
$Ro_w = 1 / ($tw[0]*$a3 + $b3) ; // Density of air = mass of dry air per unit volume of moist air, kg/m3 (saturated at water surface temperature)
                                 // This is the density in psychrometric charts and tables

if ($Ro_r - $Ro_w  <= 0.02) {
    $C = 40.0 ; // Coefficient in SI units
} else {
    $C = 35.0 ; // Coefficient in SI units
}
$debit3 = $C * $Ro_w * pow(($Ro_r-$Ro_w), 1/3) * ($W_w - $W_r) ; // kg/hr*m2
$loss3 = $debit3*$surf*24 ; // Perte (kg = l) par jour
$level3 = $loss3/$surf ; // Baisse de niveau (mm)

// E0= 0.00005*(pw-pr) : Equation (2) - pr =  partial pressure of water vapor in air, at air temperature and humidity
$B =  0.00005 ; // In SI units
$debit4 = $B * ($pw - $pa) ; // kg/hr*m2
$loss4 = $debit4*$surf*24 ; // Perte (kg = l) par jour
$level4 = $loss4/$surf ; // Baisse de niveau (mm)

// ****************************************************************************
$level5 = max($level2, $level3, $level4) ; // Valeur maximum des équations 1, 2 et 7 (Mirza Mohammed Shah)
$level = ($level1 + $level5 ) / 2 ; // Valeur moyenne

if ($level <= 0.0) {
    $level = 0.0 ;
}

 // Mise à jour sur l'Eedomus
maj_dom($periph_id1,$level) ;

// ****************************************************************************

function dew_point($celsius, $rh) {
// http://www.eol.ucar.edu/projects/ceop/dm/documents/refdata_report/eqns.html (Bolton 1980)
// Retourne le point de rosée (degrés celsius) en fonction de la température (celsius) et de l'humidité relative (% : PAS proportion) :
  global $dew ;
  $dew = log((6.112*exp((17.67*$celsius)/($celsius+243.5)))*($rh/100)/6.112)*243.5/(17.67-log((6.112*exp((17.67*$celsius)/($celsius+243.5)))*($rh/100)/6.112)) ;
  return $dew ;
}

function latent_heat($celsius) {
// https://www.researchgate.net/publication/267803552_Climate_parameters_used_to_evaluate_the_evapotranspiration_in_delta_central_zone_of_Egypt
// Retourne la chaleur latente de vaporisation (kJ/kg) en fonction de la température de l eau (degrés celsius) :
  global $lath ;
  $lath = (2.5010-2.3664*pow(10,-3)*$celsius)*1000 ;
  return $lath ;
}

function vapor_sat($celsius) {
// https://fr.wikipedia.org/wiki/Pression_de_vapeur_saturante_de_l%27eau
// Retourne la pression de vapeur saturante suivant l équation d Antoine en mmHg :
  global $sat ;
  $sat = pow(10,8.07131-((1730.63/(233.426+$celsius)))) ;
  return $sat ;
}

function maj_dom( $periph, $val )
{
   global $api_user;
   global $IPeedomus;
   global $api_secret;
//   $val = str_replace(' ', '%20', $val);
   $url = "https://".$IPeedomus."/set?action=periph.value";
   $url .= "&api_user=$api_user";
   $url .= "&api_secret=$api_secret";
   $url .= "&periph_id=$periph";
   $url .= "&value=$val";

// Mis à jour du périphérique
   $result = file_get_contents($url);

   if (strpos($result, '"success": 1') == false)
   {
     echo "Une erreur est survenue lors de la mise à jour [".$result."]";break;
   }
}

?>
Herbert
 
Messages : 27
Inscription : 16 Août 2018

Retour vers Scripts & Périphériques du store

Qui est en ligne ?

Utilisateurs parcourant ce forum : Aucun utilisateur inscrit et 24 invité(s)