{"id":1954,"date":"2021-12-24T11:46:15","date_gmt":"2021-12-24T10:46:15","guid":{"rendered":"http:\/\/sickel.net\/blogg\/?p=1954"},"modified":"2021-12-27T15:38:46","modified_gmt":"2021-12-27T14:38:46","slug":"hold-oversikt-over-stromforbruket-med-data-fra-tibber","status":"publish","type":"post","link":"http:\/\/sickel.net\/blogg\/?p=1954","title":{"rendered":"Hold oversikt over str\u00f8mforbruket med data fra Tibber"},"content":{"rendered":"\n<p>Jeg skaffet en <a rel=\"noreferrer noopener\" href=\"https:\/\/tibber.com\/no\/store\/produkt\/pulse\" target=\"_blank\">Tibber Pulse<\/a> som jeg koblet opp i sikringsskapet. Den  m\u00e5ler str\u00f8mforbruket hvert 2.5 sekunder og jeg kan f\u00e5 tak i de dataene. Jeg kan holde\u00f8ye med forbruket og ogs\u00e5 se dette sammen med fremtidig str\u00f8mpris og temperatur. Jeg seteter opp et dashboard i <a href=\"https:\/\/grafana.com\">Grafana<\/a>. Serversystemene kj\u00f8res p\u00e5 en linux server jeg har g\u00e5ende. N\u00f8yaktig det samme oppsettet skal kunne kj\u00f8res p\u00e5 de fleste nyere linux systemer som bruker systemd (inkludert rasbian p\u00e5 rasberry pi). Dersom du bruker et system som ikke har systemd, vil alt fungere med unntak av oppsettet for autostart. For \u00e5 hente inn v\u00e6rvarsel,se <a rel=\"noreferrer noopener\" href=\"http:\/\/sickel.net\/blogg\/?p=1923\" target=\"_blank\">http:\/\/sickel.net\/blogg\/?p=1923<\/a>. <\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-09-16-36-Momentanforbruk-Grafana.png\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"510\" data-attachment-id=\"1955\" data-permalink=\"http:\/\/sickel.net\/blogg\/?attachment_id=1955\" data-orig-file=\"http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-09-16-36-Momentanforbruk-Grafana.png\" data-orig-size=\"960,510\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Screenshot-2021-12-24-at-09-16-36-Momentanforbruk-Grafana\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-09-16-36-Momentanforbruk-Grafana.png\" src=\"http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-09-16-36-Momentanforbruk-Grafana.png\" alt=\"\" class=\"wp-image-1955\" srcset=\"http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-09-16-36-Momentanforbruk-Grafana.png 960w, http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-09-16-36-Momentanforbruk-Grafana-300x159.png 300w, http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-09-16-36-Momentanforbruk-Grafana-768x408.png 768w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n\n\n\n<p>Inntil videre tar jeg omveien via Tibbers skyl\u00f8sning. <a href=\"https:\/\/github.com\/Danielhiversen\/pyTibber\">PyTibber<\/a> gir et oppsett som gj\u00f8r dette enkelt. Da kan data hentes inn enkelt etter et &#8220;pip install tibber&#8221;:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#!\/usr\/bin\/python3\n\nimport asyncio\nimport aiohttp\nimport tibber\nimport json  \n\nACCESS_TOKEN = \"Tibber access token\"\nFILE='\/var\/www\/html\/homelog2\/pulse.json'\n# Can be picked up by my webserver\n\nasync def _callback(pkg):\n    data = pkg.get(\"data\")\n    if data is None:\n        return\n    pulsedata=data.get(\"liveMeasurement\")\n    with open(FILE,'w') as outfile:\n        json.dump(pulsedata,outfile)\n    \n\nasync def run():\n    async with aiohttp.ClientSession() as session:\n        tibber_connection = tibber.Tibber(ACCESS_TOKEN, websession=session)\n        await tibber_connection.update_info()\n    home = tibber_connection.get_homes()[0]\n    await home.rt_subscribe(_callback)\n\nif __name__ == '__main__':\n    loop = asyncio.get_event_loop()\n    asyncio.ensure_future(run())\n    loop.run_forever()<\/pre>\n\n\n\n<p>Dette scriptet henter data fortl\u00f8pende og lagrer det som en json fil i en katalog som serves av en http-server. Jeg \u00f8nsker at dette skal kj\u00f8re kontinuerlig og starte automatisk om serveren starter om, s\u00e5 jeg har kopiert pythonscriptet til \/usr\/local\/bin og definert en service-fil:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[Unit]\nDescription=Tibber pulse collector\nAfter=network-online.target\nWants=network-online.target systemd-networkd-wait-online.service\nStartLimitIntervalSec=500\nStartLimitBurst=5\n\n[Service]\nType=simple\nExecStart=\/usr\/local\/bin\/tibberpulse.py\nUser=morten\nRestart=on-failure\nRestartSec=5s\n\n[Install]\nWantedBy=multi-user.target<\/pre>\n\n\n\n<p>Dette er lagret som \/etc\/systemd\/system\/tibberpulse.service. For \u00e5 f\u00e5 dette til \u00e5 kj\u00f8re, m\u00e5 man fortelle systemd at det finnes nye service-filer, s\u00e5 starte servicen og til slutt sette at den skal startes med reboot. Dette er f\u00f8lgende kommandoer:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo systemctl daemon-reload\nsudo systemctl start tibberpulse.service\nsudo systemctl enable tibberpulse.service<\/pre>\n\n\n\n<p>Da kan man skjekke at servicen kj\u00f8rer:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">morten@sjest:~(master)$ systemctl status tibberpulse.service \n\u25cf tibberpulse.service - Tibber pulse collector\n     Loaded: loaded (\/etc\/systemd\/system\/tibberpulse.service; enabled; vendor preset: enabled)\n     Active: active (running) since Sat 2021-12-18 17:27:59 CET; 5 days ago\n   Main PID: 120163 (tibberpulse.py)\n      Tasks: 2 (limit: 19086)\n     Memory: 28.3M\n        CPU: 6min 24.729s\n     CGroup: \/system.slice\/tibberpulse.service\n             \u2514\u2500120163 \/usr\/bin\/python3 \/usr\/local\/bin\/tibberpulse.py\n\nDec 22 18:02:10 sjest tibberpulse.py[120163]:   File \"\/home\/morten\/.local\/lib\/python3.9\/site-packages\/graphql_subsc&gt;\nDec 22 18:02:10 sjest tibberpulse.py[120163]:     msg = await asyncio.wait_for(self.websocket.recv(), timeout=30)\nDec 22 18:02:10 sjest tibberpulse.py[120163]:   File \"\/usr\/lib\/python3.9\/asyncio\/tasks.py\", line 481, in wait_for\nDec 22 18:02:10 sjest tibberpulse.py[120163]:     return fut.result()\nDec 22 18:02:10 sjest tibberpulse.py[120163]:   File \"\/home\/morten\/.local\/lib\/python3.9\/site-packages\/websockets\/le&gt;\nDec 22 18:02:10 sjest tibberpulse.py[120163]:     await self.ensure_open()\nDec 22 18:02:10 sjest tibberpulse.py[120163]:   File \"\/home\/morten\/.local\/lib\/python3.9\/site-packages\/websockets\/le&gt;\nDec 22 18:02:10 sjest tibberpulse.py[120163]:     raise self.connection_closed_exc()\nDec 22 18:02:10 sjest tibberpulse.py[120163]: websockets.exceptions.ConnectionClosedError: no close frame received &gt;\nDec 23 00:08:01 sjest tibberpulse.py[120163]: No data, reconnecting.<\/pre>\n\n\n\n<p>Den har feilet noen ganger, men har blitt startet opp igjen og har kj\u00f8rt uten problemer i halvannet d\u00f8gn. (Feilen 22 skyldes sannsynligvis at jeg koblet om en nettverkskabel, den burde v\u00e6rt h\u00e5ndtert med en try &#8211; except)<\/p>\n\n\n\n<p>Jeg vil ogs\u00e5 ha inn data om n\u00e5v\u00e6rend og fremtidig str\u00f8mpris. For \u00e5 gj\u00f8re ting enkelt, henter jeg inn dette en gang i timen med crontab (fyll inn egen Tibber-token):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">1 * * * * \/usr\/bin\/curl -H \"Authorization: Bearer Tibber-token\" -H \"Content-Type: application\/json\" -X POST -d '{\"query\":\"{ viewer { homes { currentSubscription{ priceInfo{ current{ total energy tax startsAt } today { total energy tax startsAt } tomorrow { total energy tax startsAt } } } } } }\"}' https:\/\/api.tibber.com\/v1-beta\/gql &gt; \/var\/www\/html\/homelog2\/cost.json<\/pre>\n\n\n\n<p>I grafana lager jeg tre datakilder basert p\u00e5 JSON-API som henter inn pulse.json, cost.json og weather.json fra webserveren min. For viserinstrumenetene, er det bare sp\u00f8rring etter et parameter,som eksempel for aktult effekttrekk:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-11-33-07-Momentanforbruk-Grafana.png\"><img loading=\"lazy\" decoding=\"async\" width=\"620\" height=\"303\" data-attachment-id=\"1961\" data-permalink=\"http:\/\/sickel.net\/blogg\/?attachment_id=1961\" data-orig-file=\"http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-11-33-07-Momentanforbruk-Grafana.png\" data-orig-size=\"620,303\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Screenshot-2021-12-24-at-11-33-07-Momentanforbruk-Grafana\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-11-33-07-Momentanforbruk-Grafana.png\" src=\"http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-11-33-07-Momentanforbruk-Grafana.png\" alt=\"\" class=\"wp-image-1961\" srcset=\"http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-11-33-07-Momentanforbruk-Grafana.png 620w, http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-11-33-07-Momentanforbruk-Grafana-300x147.png 300w\" sizes=\"auto, (max-width: 620px) 100vw, 620px\" \/><\/a><\/figure>\n\n\n\n<p>De to andre blir litt mer kompliserte, for aktuell str\u00f8mpris er Field<br \/>$.data.viewer.homes[*].currentSubscription.priceInfo.current.total<\/p>\n\n\n\n<p>og for temperatur er det <br \/>$.properties.timeseries[*].data.instant.details.air_temperature<\/p>\n\n\n\n<p>For tidsserien m\u00e5 jeg b\u00e5de hente inn tidspunkt og verdi: <\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-11-38-50-Momentanforbruk-Grafana.png\"><img loading=\"lazy\" decoding=\"async\" width=\"749\" height=\"440\" data-attachment-id=\"1962\" data-permalink=\"http:\/\/sickel.net\/blogg\/?attachment_id=1962\" data-orig-file=\"http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-11-38-50-Momentanforbruk-Grafana.png\" data-orig-size=\"749,440\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Screenshot-2021-12-24-at-11-38-50-Momentanforbruk-Grafana\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-11-38-50-Momentanforbruk-Grafana.png\" src=\"http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-11-38-50-Momentanforbruk-Grafana.png\" alt=\"\" class=\"wp-image-1962\" srcset=\"http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-11-38-50-Momentanforbruk-Grafana.png 749w, http:\/\/sickel.net\/blogg\/wp-content\/2021\/12\/Screenshot-2021-12-24-at-11-38-50-Momentanforbruk-Grafana-300x176.png 300w\" sizes=\"auto, (max-width: 749px) 100vw, 749px\" \/><\/a><\/figure>\n\n\n\n<p>Den \u00f8verste henter (resten av) dagens str\u00f8mpriser, den midterste henter temperaturvarsel (JSON API er et navn jeg satt p\u00e5 datakilden f\u00f8r jeg forsto hvordan den navningen fungerer. Hadde jeg satt det opp  n\u00e5, ville den hett &#8220;metdata&#8221;). Den siste henter morgendagens str\u00f8mpriser.<\/p>\n\n\n\n<p>For klipp og lim:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$.data.viewer.homes[].currentSubscription.priceInfo.today[].startsAt\n$.data.viewer.homes[*].currentSubscription.priceInfo.today[*].total\n$.properties.timeseries[*].time\n$.properties.timeseries[*].data.instant.details.air_temperature\n$.data.viewer.homes[*].currentSubscription.priceInfo.tomorrow[*].startsAt\n$.data.viewer.homes[*].currentSubscription.priceInfo.tomorrow[*].total<\/pre>\n\n\n\n<p>Dersom man av en eller annen grunn \u00f8nsker seg str\u00f8mprisen uten avgifter, bruk &#8220;energy&#8221; i stedet for &#8220;total&#8221; i de aktuelle felten<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Jeg skaffet en Tibber Pulse som jeg koblet opp i sikringsskapet. Den m\u00e5ler str\u00f8mforbruket hvert 2.5 sekunder og jeg kan f\u00e5 tak i de dataene. Jeg kan holde\u00f8ye med forbruket og ogs\u00e5 se dette sammen med fremtidig str\u00f8mpris og temperatur. &hellip; <a href=\"http:\/\/sickel.net\/blogg\/?p=1954\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1954","post","type-post","status-publish","format-standard","hentry","category-div"],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/pnVtD-vw","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"http:\/\/sickel.net\/blogg\/index.php?rest_route=\/wp\/v2\/posts\/1954","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/sickel.net\/blogg\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/sickel.net\/blogg\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/sickel.net\/blogg\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/sickel.net\/blogg\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1954"}],"version-history":[{"count":8,"href":"http:\/\/sickel.net\/blogg\/index.php?rest_route=\/wp\/v2\/posts\/1954\/revisions"}],"predecessor-version":[{"id":1966,"href":"http:\/\/sickel.net\/blogg\/index.php?rest_route=\/wp\/v2\/posts\/1954\/revisions\/1966"}],"wp:attachment":[{"href":"http:\/\/sickel.net\/blogg\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1954"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/sickel.net\/blogg\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1954"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/sickel.net\/blogg\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1954"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}