106 057 läst · 236 svar
106k läst
236 svar
Mätning med 1-wire
En sen uppdatering. Min nätleverantör, Skånska Energi, var ute och bytte elmätare för ett tag sedan. Fick då utdraget två tåtar från S0-utgången på elmätaren för inkommande i huset. Tack så mycketphl skrev:Har i dagsläget ingen loggning på elmätaren på inkommande elmätare men det är mest beroende på ren lathet. Brukar dra hem värdena automagiskt via mitt login hos min nätleverantör. Dock ska Skånska Energi bryta plomberingen på elmätaren nästa vecka så med lite tur kan man få smussla in två trådar till S0-plinten så slipper jag fototransistorer och skit.
Ett år gammal tråd, men kan läsa mig till att det finns många duktiga på php, MySQL etc i denna tråden... Så jag lyfter den till ytan igen.
Jag har ett litet 1-wire (fyra temp och två räknare) nät där jag skriver till en MySQL.
Hade tänkt plotta datat i en graph mha JPgraph, men får inte ut datum i x-axeln som jag vill.
Har fem kolumner i tabellen, datum genereras av mysql de andra är 1-wire mätarna, en per kolumn.
| 2011-12-10 10:50:12 | 22.125 | 22.125 | 21.125 | 6.4375 |
Att få in temperaturerna är inga problem, men fattar inte hur man får den korrekta tiden i x-axeln?
Så här ser det ut idag (se bild), se tiden på x-axeln och ovanför tabellen. Det stämmer inte.
Såhär ser min (stulna) kod ut...
Jag har ett litet 1-wire (fyra temp och två räknare) nät där jag skriver till en MySQL.
Hade tänkt plotta datat i en graph mha JPgraph, men får inte ut datum i x-axeln som jag vill.
Har fem kolumner i tabellen, datum genereras av mysql de andra är 1-wire mätarna, en per kolumn.
| 2011-12-10 10:50:12 | 22.125 | 22.125 | 21.125 | 6.4375 |
Att få in temperaturerna är inga problem, men fattar inte hur man får den korrekta tiden i x-axeln?
Så här ser det ut idag (se bild), se tiden på x-axeln och ovanför tabellen. Det stämmer inte.
Såhär ser min (stulna) kod ut...
Jag vill få ut den korrekta tiden i x-axeln, men hur?<?php
include ("/jpgraph.php");
include ("/jpgraph_line.php");
mysql_connect("localhost", "xxxxxx", "xxxxx") or die("Kan ej ansluta: " . mysql_e rror());
mysql_select_db("1wire") or die("Kan ej öa databas 1wire");
if (isset($_GET['From'])) {
$fran = $_GET['From'];
$till = $_GET['To'];
} elseif (isset($_GET['Day'])) {
$fran = Date("Y-m-d H:i",strtotime($_GET['Day']));
$till = Date("Y-m-d H:i",strtotime($fran) +(1 * 24 * 60 * 60));
}
else {
$till = Date("Y-m-d H:i", time());
$fran = Date("Y-m-d H:i",strtotime($till) - (1 * 24 * 60 * 60));
}
$query = "SELECT * FROM temps WHERE timestamp >= '$fran' and timestamp < '$till' ";
$result = mysql_query($query) or die("SQL frå felaktig: " . mysql_error());
for ($i=strtotime($fran); $myrow=mysql_fetch_row($result); $i = $i + 40) {
$ydataa[] = $myrow[1];
$ydatab[] = $myrow[2];
$ydatac[] = $myrow[3];
$ydatad[] = $myrow[4];
$xdata[] = Date("H:i", $i);
}
// Create the graph. These two calls are always required
$graph = new Graph(800,550,"auto");
// $graph = new Graph(1024,600,"auto");
// x-axel skalan
$graph->SetScale("textlin",-20,35);
$graph->title->Set("Temperaturer: ".Date("Y-m-d H:i",strtotime($fran))." -> ".D ate("Y-m-d H:i",strtotime($till)));
$graph ->img->SetMargin(40,20,30,70);
$graph ->xgrid->Show(true,false);
$graph ->xaxis->SetTextTickInterval(40);
$graph ->xaxis->SetTextLabelInterval(1);
$graph ->xaxis->SetTickLabels($xdata);
$graph ->xaxis->SetFont(FF_FONT1,FS_BOLD,9);
// $graph ->xaxis->SetFont(FF_FONT0);
// $graph ->xaxis->SetLabelAngle(30);
// $graph ->xaxis->HideFirstTicklabel();
$graph ->xaxis->SetLabelMargin(41);
$graph ->xaxis->SetLabelMargin(145);
$graph ->yaxis->title->Set("Grader");
$graph ->yaxis->title->SetFont(FF_FONT1,FS_BOLD);
$graph ->SetShadow();
$graph ->legend->SetLayout(LEGEND_HOR);
$graph ->legend->Pos(.5,.90,"center","center");
$graph ->legend->Pos(.5,.94,"center","center");
$graph ->ygrid->Show(true,true);
// $graph->ygrid->SetFill(true,'#EFEFEF@0.5','#BBCCFF@0.5');
// Create the linear plot
$lineplot1=new LinePlot($ydataa);
$lineplot1->SetColor("black");
$lineplot1 ->SetLegend("Server Room");
$lineplot1 ->setfaststroke();
// Create the linear plot
$lineplot2=new LinePlot($ydatab);
$lineplot2->SetColor("red");
$lineplot2 ->SetLegend("Lower Hall");
$lineplot2 ->setfaststroke();
// Create the linear plot
$lineplot3=new LinePlot($ydatac);
$lineplot3->SetColor("blue");
$lineplot3 ->SetLegend("Upper Hall");
$lineplot3 ->setfaststroke();
// Create the linear plot
$lineplot4=new LinePlot($ydatad);
$lineplot4->SetColor("green");
$lineplot4 ->SetLegend("Outside");
$lineplot4 ->setfaststroke();
// Add the plot to the graph
$graph->Add($lineplot1);
$graph->Add($lineplot2);
$graph->Add($lineplot3);
$graph->Add($lineplot4);
// Display the graph
$graph->Stroke();
?>
Medlem
· Västernorrland
· 2 057 inlägg
Det jag inte riktigt greppar är utläsningen av resultatet från mySql selecten.
Dvs:
Så mina tips är:
- Använd det faktiska datum som finns i första kolumnen.
- Använd inte for-loop för att läsa ut resultat från databassökningen. Alla rader ska läsas så använd lämpligtvis en foreach istället. Om det är så att du inte är intresserad av alla rader så är det SELECT-satsen som ska förändras till att bara söka ut det du vill.
Dvs:
Du räknar upp tid/datum själv för varje rad istället för att använda det datum som finns lagrat i första kolumnen. Det leder ofelbart till mismatch då det nödvändigtvis inte är samma tid/datum i loopen som finns lagrat på den raden du läser ut.
Så mina tips är:
- Använd det faktiska datum som finns i första kolumnen.
- Använd inte for-loop för att läsa ut resultat från databassökningen. Alla rader ska läsas så använd lämpligtvis en foreach istället. Om det är så att du inte är intresserad av alla rader så är det SELECT-satsen som ska förändras till att bara söka ut det du vill.
Tack it-snubben for den "heads up", borde jag ju sett! :blushing:
Nåja, man är nybörjare på php så det är förlåtande...
Löste det på detta sättet:
Nåja, man är nybörjare på php så det är förlåtande...
Löste det på detta sättet:
Verkar ju fungera bättre när man läser tiden från databasen istället...
Medlem
· Västernorrland
· 2 057 inlägg
Kul att du fick till det. Nybörjarmissar gör allagadu^ skrev:Löste det på detta sättet:
$query = "SELECT * FROM newtemps";
$result = mysql_query($query) or die("SQL fraga felaktig: " . mysql_error());
while($myrow = mysql_fetch_array($result))
{
$xdata[] = $myrow[1];
$ydataa[] = $myrow[2];
$ydatab[] = $myrow[3];
$ydatac[] = $myrow[4];
$ydatad[] = $myrow[5];
}
WHILE är en mycket bättre variant.
Lite småtips (allt för att göra det enklare att underhålla kod)
:
- i ovanstående select-sats så gör du en "SELECT * FROM...". Visserligen fungerar det men det man gör då är läser ut ALLA kolumner i den ordningen som de ligger i databasen. Det är alltså databasens struktur som bestämmer VAD som är myrow[0], myrow[1] etc.
Det är bättre att alltid specificera vilka kolumner du är intresserad av och i vilken ordning. Om du då senare skulle ändra i databasens struktur så påverkar det inte befintlig kod. Dvs gör SELECT namn_kolumn0, namn_kolumn1 [... osv]
- Ännu bättre är att ange ett alias i select-satsen för varje kolumn, göra en fetch_assoc och därefter använda peka på aliasnamnet istället for myrow[0], myrow[1]...
Alltså:
SELECT namn_kolumn0 AS "tidkod", namn_kolumn1 as "temp1"... FROM...
while($myrow = mysql_fetch_assoc($result)) {
$xdata[] = $myrow["tidkod"];
$ydataa[] = $myrow["temp1"];
}
(nu vet jag ju inte vad namnen är på resp kolumn i din databas så jag skrev bara "namn_kolumnX" som exempel)
Hoppas att du förstår vad jag menar i mina "småtips".
Redigerat:
Japp, helt med. Faktum är att jag gjorde denna selektiva "select" från databasen i en annan graf efter att jag fick x-axeln i ordning. Bra tips om alias, skall prova det!
Ett annat "bekymmer" jag inte påbörjat än är pulsmätningarna från elmätare. Har förberett genom att ta in antal pulser räknaren har gjort vid givna tidpunkter. Men för att få den aktuella förbrukningen vid varje tidangivelse så måste man ju räkna nuvarande antal pulser minus föregående tidangivelsens pulser delat på pulser per KWh, eller liknande. Men kan man göra den beräkningen direkt som en query och i så fall hur?
Alla tips välkomnas!
Ett annat "bekymmer" jag inte påbörjat än är pulsmätningarna från elmätare. Har förberett genom att ta in antal pulser räknaren har gjort vid givna tidpunkter. Men för att få den aktuella förbrukningen vid varje tidangivelse så måste man ju räkna nuvarande antal pulser minus föregående tidangivelsens pulser delat på pulser per KWh, eller liknande. Men kan man göra den beräkningen direkt som en query och i så fall hur?
Alla tips välkomnas!
Så här gör jag:
Detta är inte optimalt men det fungerar. Jag hämtar alltså ut den sista raden och den 3e sista raden. Detta för att jag tycker det blir för nära ananrs. Jag hämtar mina värden varje minut. Så det nuvarande värdet är baserat på över 3 minuter.3 select
4 (
5 (
6 SELECT value
7 FROM `value`
8 WHERE sensor_serial = '1D72DE0C000000DB'
9 ORDER BY `value`.`dt` DESC
10 LIMIT 1 , 1
11 ) - (
12
13 SELECT value
14 FROM `value`
15 WHERE sensor_serial = '1D72DE0C000000DB'
16 ORDER BY `value`.`dt` DESC
17 LIMIT 3 , 1
18 )) * 7200 / ((
19 SELECT (
20
21 SELECT unix_timestamp( dt )
22 FROM `value`
23 WHERE sensor_serial = '1D72DE0C000000DB'
24 ORDER BY `value`.`dt` DESC
25 LIMIT 1 , 1
26 ) - (
27
28 SELECT unix_timestamp( dt )
29 FROM `value`
30 WHERE sensor_serial = '1D72DE0C000000DB'
31 ORDER BY `value`.`dt` DESC
32 LIMIT 3 , 1
33 )
34 ))
35 as momentant;
Redigerat:
Korrekt. Dt som i Datetimestamp.
Medlem
· Västernorrland
· 2 057 inlägg
Ja, absolut går det.gadu^ skrev:
Jag skulle prova gruppera resultatet i queryn i enlighet med den grupperingsstorlek jag vill ha och använda aggregatfunktionerna MIN() och MAX().
ex:
SELECT MAX(num_pulses)-MIN(num_pulses) AS "pulses_thishour" FROM xxx GROUP BY HOUR(timecode)
Ovanstående är otestat och endast en tanke om hur jag skulle börja med att lösa det. Att det gör att lösa med endast SQL tar jag för givet.
it-snubben, provade det rakt av som hastigast men fick det inte att gå ihop...
Funderat lite på att om det inte möjligt att beräkna ett delta, lite ungefär som danielr112 gör ovan, men lite enklare... Räkna ett average över tidsperiod är ju enklare.
Funderat lite på att om det inte möjligt att beräkna ett delta, lite ungefär som danielr112 gör ovan, men lite enklare... Räkna ett average över tidsperiod är ju enklare.
Hans funkar men om jag inte ser helt rätt är den helt beroende på att värdena matas in i databasen vid specifika tider. Ska man kolla en tid per minut kan det skilja några sekunder när värdet är inmatat. (Ivf i mitt fall där jag pollar 100 sensorer) Och då kan ett par sekunder göra stor skillnad. Därav att jag läser av tiden också i själva sqlen och får då fram tiden.
Har en enkel databas för elen med en tabell med dessa kolumner
(Senaste rader ser ut såhär)
| Date | house | home
| 2011-12-12 07:50:03 | 398938 | 314927 | NULL | NULL |
| 2011-12-12 07:55:03 | 398956 | 314944 | NULL | NULL |
| 2011-12-12 08:00:06 | 398973 | 314976 | NULL | NULL |
| 2011-12-12 08:05:03 | 398988 | 315015 | NULL | NULL
House och home matas med pulser från räknare A resp B.
I skrivande stund är det 2275 rader i tabellen och skriver jag
SELECT MAX(house)-MIN(house) AS "Pulses_thishour" FROM el GROUP BY HOUR(date);
Resultatet blir
+-----------------+
| Pulses_thishour |
+-----------------+
| 52987 |
| 52930 |
| 52933 |
| 52899 |
| 52946 |
| 52945 |
| 52872 |
| 52929 |
| 52791 |
| 43877 |
| 51503 |
| 52436 |
| 52495 |
| 52451 |
| 52894 |
| 52971 |
| 52956 |
| 52702 |
| 52664 |
| 52653 |
| 52646 |
| 52709 |
| 53265 |
| 53021 |
+-----------------+
24 rows in set (0.01 sec)
Räknar jag manuellt mellan 07:00 och 08:00 så får jag bara 256 pulser.
Behöver läsa på mer om MySQL...
(Senaste rader ser ut såhär)
| Date | house | home
| 2011-12-12 07:50:03 | 398938 | 314927 | NULL | NULL |
| 2011-12-12 07:55:03 | 398956 | 314944 | NULL | NULL |
| 2011-12-12 08:00:06 | 398973 | 314976 | NULL | NULL |
| 2011-12-12 08:05:03 | 398988 | 315015 | NULL | NULL
House och home matas med pulser från räknare A resp B.
I skrivande stund är det 2275 rader i tabellen och skriver jag
SELECT MAX(house)-MIN(house) AS "Pulses_thishour" FROM el GROUP BY HOUR(date);
Resultatet blir
+-----------------+
| Pulses_thishour |
+-----------------+
| 52987 |
| 52930 |
| 52933 |
| 52899 |
| 52946 |
| 52945 |
| 52872 |
| 52929 |
| 52791 |
| 43877 |
| 51503 |
| 52436 |
| 52495 |
| 52451 |
| 52894 |
| 52971 |
| 52956 |
| 52702 |
| 52664 |
| 52653 |
| 52646 |
| 52709 |
| 53265 |
| 53021 |
+-----------------+
24 rows in set (0.01 sec)
Räknar jag manuellt mellan 07:00 och 08:00 så får jag bara 256 pulser.
Behöver läsa på mer om MySQL...
Medlem
· Västernorrland
· 2 057 inlägg
Jo, mitt exempel ovan var ju just bara ett exempel. För att kunna göra en fullt fungerande SQL-sats så krävs tyvärr lite mer information om databasen och dess innehåll.
I mitt exempel utgick jag från att kolumnen med pulser innehåller det ackumulerade värdet av pulser. Alltså att varje ny post alltid innehåller ett högre värde än den posten som infogades för ca 1 minut sedan. Exemplet räknar inte ett average. Min tanke var att gruppera utsökningen i block om timmar ( GROUP BY HOUR(timecode) ) och med MAX() - MIN() ta fram skillnaden mellan det högsta och lägsta värdet inom varje grupp. Alltså hur många pulser har det ökat med under varje timme. Det jag tyvärr inte gjorde i exemplet var att sortera datat baserat på timecode vilket borde ha gjorts..
Mitt exempel är inte beroende av att värdena matas in vid specifika tider. Den är beroende av att tidskoden ska vara korrekt i avseende när värdena gällde (dvs när pollningen gjordes). Om man har en tidkrävande pollning av många sensorer och därmed får en skillnad i tid när pollningen gjordes och när man registrerar tiden så kommer det ofelbart att bli avvikelser om man bara registrerar en tidskod.
En lösning är att man accepterar detta, alltså att man vet att tidskoden betyder tiden för läsning av sista sensorn, alternativt att man skapar olika poster för varje givarpollning.
I mitt exempel utgick jag från att kolumnen med pulser innehåller det ackumulerade värdet av pulser. Alltså att varje ny post alltid innehåller ett högre värde än den posten som infogades för ca 1 minut sedan. Exemplet räknar inte ett average. Min tanke var att gruppera utsökningen i block om timmar ( GROUP BY HOUR(timecode) ) och med MAX() - MIN() ta fram skillnaden mellan det högsta och lägsta värdet inom varje grupp. Alltså hur många pulser har det ökat med under varje timme. Det jag tyvärr inte gjorde i exemplet var att sortera datat baserat på timecode vilket borde ha gjorts..
Mitt exempel är inte beroende av att värdena matas in vid specifika tider. Den är beroende av att tidskoden ska vara korrekt i avseende när värdena gällde (dvs när pollningen gjordes). Om man har en tidkrävande pollning av många sensorer och därmed får en skillnad i tid när pollningen gjordes och när man registrerar tiden så kommer det ofelbart att bli avvikelser om man bara registrerar en tidskod.
En lösning är att man accepterar detta, alltså att man vet att tidskoden betyder tiden för läsning av sista sensorn, alternativt att man skapar olika poster för varje givarpollning.
Vill du lätt ha mellan sista lästa värdena för att få ut nuvarande förbrukning använd min sql rakt av. Den kommer funka på din kod. DU kommer dock få ändra beroende på vad för antal pulser per kwh du har. Mitt exempel är för 10 000pulser / kwh