Repository navigation
Expand file tree
/
Copy path99_CLEVERPV_HEMS.pm
More file actions
104 lines (90 loc) · 3.67 KB
/
Copy path99_CLEVERPV_HEMS.pm
File metadata and controls
104 lines (90 loc) · 3.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
##############################################
# 99_CLEVERPV_HEMS.pm
#
# Pusht Momentanleistungen an die Clever-PV Generic-Push-Endpunkte
# (konfiguriert über epilot HEMS).
#
# watt = Netzleistung Hausstrom (positiv = Bezug, negativ = Einspeisung)
# producingWatt = aktuelle PV-Leistung
#
# Quellen:
# haus_ZaehlerHausstrom:power (W, OBIS 16.7.0, Intervall 30 s)
# Solar:total_pac (kW, SBFspot via Bluetooth, Intervall 600 s)
# haus_ZaehlerWaermePumpe:power (W, eigener Endpunkt, noch inaktiv)
#
# Einrichtung (FHEM-Kommandozeile):
# reload 99_CLEVERPV_HEMS
# { setKeyValue("hems_url_hausstrom", "https://push.clever-pv.com/api/v2/.../generic-push/...?code=...") }
# define hems_Push at +*00:01:00 { hemsPushCleverPv() }
#
# Wärmepumpe aktivieren, sobald die zweite Push-URL vorliegt:
# { setKeyValue("hems_url_wp", "https://push.clever-pv.com/...") }
# (kein Code-Change nötig, die Funktion prüft den Key bei jedem Lauf)
##############################################
package main;
use strict;
use warnings;
use JSON;
sub CLEVERPV_HEMS_Initialize($$) {
my ($hash) = @_;
}
# Wird minütlich vom at 'hems_Push' aufgerufen.
sub hemsPushCleverPv() {
# --- Hausstrom + PV ---
my $gridW = ReadingsVal("haus_ZaehlerHausstrom", "power", undef);
my $gridAge = ReadingsAge("haus_ZaehlerHausstrom", "power", 999999);
if (!defined $gridW) {
Log3("hems", 3, "clever-pv: skip - haus_ZaehlerHausstrom hat kein power-Reading");
} elsif ($gridAge >= 300) {
Log3("hems", 3, "clever-pv: skip - power-Reading ist ${gridAge}s alt (>300)");
} else {
my $url = getKeyValue("hems_url_hausstrom");
if (!$url) {
Log3("hems", 3, "clever-pv: skip - Keystore-Eintrag hems_url_hausstrom fehlt");
} else {
# total_pac kommt von SBFspot in kW -> Watt.
# (Einmal mittags gegenpruefen: steht dort z.B. 3.5 ist es kW,
# steht dort 3500 ist es schon W -> dann das *1000 entfernen!)
my $pvW = ReadingsVal("Solar", "total_pac", 0) * 1000;
# SBFspot pollt nur alle 10 min; erst nach 3 verpassten Abfragen
# (30 min) gilt der Wert als tot -> 0 melden, damit Clever-PV
# keinen Phantom-Ueberschuss sieht.
$pvW = 0 if ReadingsAge("Solar", "total_pac", 999999) > 1800;
# Clever-PV erwartet Integer -> runden
hemsDoPush($url, {
watt => sprintf("%.0f", $gridW) + 0,
producingWatt => sprintf("%.0f", $pvW) + 0,
});
}
}
# --- Waermepumpe: laeuft automatisch los, sobald hems_url_wp gesetzt ist ---
my $wpUrl = getKeyValue("hems_url_wp");
if ($wpUrl) {
my $wpW = ReadingsVal("haus_ZaehlerWaermePumpe", "power", undef);
hemsDoPush($wpUrl, { watt => sprintf("%.0f", $wpW) + 0 })
if defined $wpW && ReadingsAge("haus_ZaehlerWaermePumpe", "power", 999999) < 300;
}
}
# Schickt einen Payload non-blocking an einen Clever-PV-Endpunkt.
sub hemsDoPush($$) {
my ($url, $payload) = @_;
return unless $url;
Log3("hems", 5, "pushing...");
HttpUtils_NonblockingGet({
url => $url,
method => "POST",
header => { "Content-Type" => "application/json" },
data => encode_json($payload),
timeout => 10,
callback => sub {
my ($param, $err, $body) = @_;
if ($err) {
Log3("hems", 2, "clever-pv push failed: $err");
} else {
# Erfolg nur auf verbose 5, sonst spammt es das Log minuetlich voll
Log3("hems", 5, "clever-pv push ok: " . ($body // ""));
}
},
});
}
1;