And I figured out that I had to empty the buffer at the end of the cycle. But I still don’t quite know how to get the variables :noob:
At the other (non subscription) request i get a json array(?) which I then parse (?) into current price etc, but when I try to adapt the subscription in the same way I get a blank.
This is an typical string I get in return:
{„type“:„data“,„id“:„1“,„payload“:{„data“:{„liveMeasurement“:{„timestamp“:„2022-08-05T16:44:10.000+02:00“,„power“:0,„powerProduction“:942,„accumulatedConsumption“:16.138631,„accumulatedCost“:46.609486}}}}
Which is in the $data variable from the example script in the documentation.
I’ve gotten some questions as to how I did this, and I was planning to answer now, but the API at tibber has changed, and I jet again don’t know how to solve this. So my solution has stopped reporting the realtime, and accumulated consumption.
The change is the removed supprot for (the ended) graphql-ws protocol and the replacement with graphql-transport-ws protocol. I think I managed to get around that problem, by changing the protocol name, but there is now also a requirement to set user-agent header, which I don’t quite understand… As I’ve said before I have no background in programming, just what snippets I’ve managed to pick up for forums and stackexchange etc.
I’m in contact with tibber now on chat, and hopefully we can figure it out.
On the other hand. This problem is only with the current consumption, accumulated hourly consupstion data, which reqiures an subscription-connection. For the price-data I have another soulution that works just fine. It’s a script which sets three variables according to the current pricedata.
This then sets the color on the aeotec ss6 in the living-room, and on a colorbulb in the downstairs bathroom, si we always can check the pricelevel.
<?php
$pris = 12345; //variabel for pris
$nivaa = 23456; //variabel for prisnivå, 1-5 og 0 for error
$dyr = 34567; //boolsk variabel for dyr strøm, sann eller usann
$json = '{"query":"{viewer {homes {currentSubscription {priceInfo {current {total level energy tax startsAt }}}}}}"}';
# Create a connection
$ch = curl_init('https://api.tibber.com/v1-beta/gql');
# Setting our options
curl_setopt($ch, CURLOPT_URL, 'https://api.tibber.com/v1-beta/gql');
curl_setopt($ch, CURLOPT_HTTPHEADER,
array('Content-Type: application/json',
'Authorization: Bearer /*insert your token here*/')); // token
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
# Get the response
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response);
$current = $data->data->viewer->homes[0];
$level = $current->currentSubscription->priceInfo->current->level;
$total = $current->currentSubscription->priceInfo->current->total;
$energy = $current->currentSubscription->priceInfo->current->energy;
$tax = $current->currentSubscription->priceInfo->current->tax;
SetValue ($pris, $total);
switch ($level) {
case 'VERY_CHEAP':
SetValue ($nivaa, 1);
SetValue ($dyr, 0);
break;
case 'CHEAP':
SetValue ($nivaa, 2);
SetValue ($dyr, 0);
break;
case 'NORMAL':
SetValue ($nivaa, 3);
SetValue ($dyr, 0);
break;
case 'EXPENSIVE':
SetValue ($nivaa, 4);
SetValue ($dyr, 1);
break;
case 'VERY_EXPENSIVE':
SetValue ($nivaa, 5);
SetValue ($dyr, 1);
break;
default:
SetValue ($nivaa, 0);
SetValue ($dyr, 0);
}?>
This results in resonse from the tibber-server feeding the requested data every few seconds.
I then have a registervariable connected to the tibber Websocket, and the registervariable runs a script (WSforbruk) which looks like this:
<?php
//ønsker: forbruk nå, (produksjon nå), akkumulert forbruk
$usage_now = 37938;
$acc_h_usage = 18071;
// wenn das Skript von einer RegisterVariable-Instanz aus aufgerufen worden ist
if ($_IPS['SENDER'] == "RegisterVariable")
{
// bereits im Puffer der Instanz vorhandene Daten in $data kopieren
$data = RegVar_GetBuffer($_IPS['INSTANCE']);
// neu empfangene Daten an $data anhängen
$data .= $_IPS['VALUE'];
// wenn das Trennzeichen ; in $data gefunden worden ist
if (strpos($data, ';'))
{
// $data in durch ; separierte Datensätze zerlegen
$datasets = explode(';', $data);
// alle nicht durch ; terminierten Datensätze ausgeben
for ($i = 0; $i < count($datasets) - 1; $i++)
{
echo "empfangener Datensatz: ".$datasets[$i]."\n";
}
// $data auf den Inhalt des letzten (unvollständigen) Datensatzes setzen
$data = $datasets[count($datasets) - 1];
}
$data2 = json_decode($data);
$accumul = $data2->payload->data->liveMeasurement->accumulatedConsumptionLastHour;
$consumption = $data2->payload->data->liveMeasurement->power;
$ts = $data2->payload->data->liveMeasurement->timestamp;
$sale = $data2->payload->data->liveMeasurement->powerProduction;
SetValue ($acc_h_usage, $accumul);
if ($consumption > 0) {
SetValue ($usage_now, $consumption);
} else {
if ($sale !=null){
SetValue ($usage_now, 0-$sale);
}
};
RegVar_SetBuffer($_IPS['INSTANCE'], null);
};
I don’t quite understand all of this script, but it gives me my current usage og sale from the solar panels and the accumulated usage for the current hour put into the two variables defined at the top.
the WS-connection is a bit fragile. I have to wait for „‚connection_ack‘“ before I can reguest the data, or I’ll get an error message. Hence the sleep (5); which seem to work.
If I lose the connection with the tibber WS-server I have to wait for the WS to be „OPEN“ (in the message coloumn in debug) or I won’t get the connection_ack and I get no data. Prior to the change the made this winter I just checked if the data in „forbruk nå“-varable was more than 6 minutes old, and if it was, just reinitialize the connection. But now if I don’t time the reinitialization to the „opened“ message I dont get a new connection.
Is there a way to either monitor the „opened“ message and the run the connection inizialization, og through a script deactivate and reactivate the WS-client? Or to make an if 12345 is erroneous then (…)?
And of course: Is this an acceptable solution, or should it be reworked?
Thats fron a debug on the websocket? You have to time the script to when it’s „opened“, then you’ll end up with the „connection_ack“ message, and the requst for the subscription can be sent.
I changed my openWS script to work around this issue:
// Sjekke om det er mer enn 6 min siden TibberWS er oppdatert
$tib_forbruk = 37938;
$ws=34873;
$time = date(IPS_GetVariable($tib_forbruk)['VariableUpdated']);
$time = time() - $time; // to get the time since that moment
if ($time > 360)
// slå av og på WS, slik at den kommer i "opened"
{
sleep (2);
IPS_SetProperty ($ws, 'Active', 0);
IPS_ApplyChanges($ws);
sleep (2);
IPS_SetProperty ($ws, 'Active', 1);
IPS_ApplyChanges($ws);
sleep (2);
// autentisitere og starte subscription
$json = '{"type":"connection_init","payload":{"token":"<insert your token here>"}}';
WSC_SendMessage ($ws, $json);
sleep (5);
$query= '{"id": "1","type": "subscribe","payload": {"query": "subscription{liveMeasurement(homeId:\"<insert your homeId here>\"){timestamp power powerProduction accumulatedConsumptionLastHour accumulatedCost}}"}}';
WSC_SendMessage ($ws, $query);
}
It might not be up to best practice in PHP (feel free to prettyfy, anybody), but I think it does the trick. Try it out, and please report back wheter it worked or not.
As this script checks wheter the data from tibber is quite recent, I think it’s safe to run it every 4 minutes, to check. If the data’s updated it just closes, right?
I suppose you could be able to use that? If I understand correctly, the code above is frequently reconnecting which is not nice. You should set up the connection for listening once and then let the server send you messages.