Skip to content

Instantly share code, notes, and snippets.

@kulheimzb
Created October 22, 2024 13:37
Show Gist options
  • Save kulheimzb/cfe8c21214c80cdab579c7719bc56136 to your computer and use it in GitHub Desktop.
Save kulheimzb/cfe8c21214c80cdab579c7719bc56136 to your computer and use it in GitHub Desktop.
Connecting Tecomat Foxtrot to Home Assistant via MQTT
VAR_GLOBAL CONSTANT
MAX_SENSORS : USINT := 17;
MAX_STRING : USINT := 20;
END_VAR
TYPE
T_SENSOR : STRUCT
name : string [30];
val : STRING[MAX_STRING]; // aktualni STRING hodnota
preVal : STRING[MAX_STRING]; // predchozi STRING hodnota
END_STRUCT;
T_SENSORS : ARRAY [1..MAX_SENSORS] OF T_SENSOR;
END_TYPE
PROGRAM prgMqtt
VAR_INPUT
//sendcomPub : BOOL R_EDGE := 0;
//subRqSub : BOOL R_EDGE := 0;
END_VAR
VAR
connect : bool := true;
MQTTPub : fbMQTTPublisher;
MQTTSub : fbMQTTSubscriber;
sent : BOOL := false; // zda bylo odeslano
brokerIPaddr : STRING := 'x.x.x.x';
remotePort : UINT := 1883;
localPortPub : UINT := 60000;
localPortSub : UINT := 50000;
loginName : string[32] := '';
loginPass : string[32] := '';
comparamPub : T_MQTT_COM_PARAM := (pRetain := true, qos := 1, dup := false, clean := false);
comparamSub : T_MQTT_COM_PARAM;
// na prvnim miste je zdroj dat
topicPub : string[80] := 'xxxxx';
topicSub : string[80] := 'ha/xxxxx/#';
dataPub : string[255] := '';
dataSub : string[255] := '';
// aktualni sensor
i : USINT := 1;
// predchozi hodnota pro temperature senzory
tempsensors : ARRAY [1..8] OF REAL := [-99,-99,-99,-99,-99,-99,-99,-99];
// string hodnota senzoru
sensors : T_SENSORS := [// pocet teplomeru musi souhlasit s tempsensors
(name:= 'tempKotel', preVal:='-'),
(name:= 'tempObyvC', preVal:='-'),
(name:= 'tempP24', preVal:='-'),
(name:= 'tempP20', preVal:='-'),
(name:= 'tempP17', preVal:='-'),
(name:= 'tempHost', preVal:='-'),
(name:= 'tempGaraz', preVal:='-'),
(name:= 'tempKoupelna2', preVal:='-'),
// konec teplot
(name:= 'Cerpadlo1', preVal:='-'),
(name:= 'Cerpadlo2', preVal:='-'),
(name:= 'CerpadloTopna', preVal:='-'),
(name:= 'VztTopeni', preVal:='-'),
(name:= 'Kotel', preVal:='-'),
(name:= 'HDO', preVal:='-'),
(name:= 'HJ306_1stupen', preVal:='-'),
(name:= 'VztBypass', preVal:='-'),
(name:= 'VztMode', preVal:='-')
];
END_VAR
VAR_TEMP
dateTimeRTC : DATE_AND_TIME;
processValue : BOOL;
bval : BOOL; // aktualni BOOL hodnota senzoru
rval : REAL; // aktualni REAL hodnota senzoru
sval : STRING[MAX_STRING]; // aktualni STRING hodnota senzoru
preRval : REAL; //predchozi REAL hodnota
END_VAR
// presunout do one time init
MQTTPub(chanCode := ETH1_UNI0,
brokerIP := STRING_TO_IPADR(brokerIPaddr),
brokerPort := remotePort,
localPort := localPortPub,
connect := connect,
//keepAlive := keepAlive,
//keepAliveInterval := keepAliveInterval,
//pingInterval := pingInterval,
//connTimeOut := connTimeOut,
comparam := comparamPub,
//loginName := loginName,
//loginPass := loginPass,
dataTxt := dataPub,
topicTxt := topicPub,
//sendCom := sendCom,
);
IF MQTTPub.connected_to_broker THEN
// zopakuj poslani minule hodnoty
IF MQTTPub.err AND sent THEN
MQTTPub.sendcom := true;
END_IF;
// posun na další hodnotu
IF MQTTPub.ok THEN
sensors[i].preVal:= sensors[i].val;
i := i+1;
IF i > MAX_SENSORS THEN i := 1; END_IF;
sent:= false;
END_IF;
// posli pripadnou dalsi hodnotu
IF not MQTTPub.busy THEN
// nacteni aktualnich hodnot
CASE i OF
// REAL_TO_STRINGF (nový doplnit níže do CASE i OF ...)
1 : rval := tempKotel;
2 : rval := tempObyvC;
3 : rval := tempP24;
4 : rval := tempP20;
5 : rval := tempP17;
6 : rval := tempHost;
7 : rval := tempGaraz;
8 : rval := tempKoupelna2;
// BOOL_TO_STRING
9 : bval := Cerpadlo1;
10 : bval := Cerpadlo2;
11 : bval := CerpadloTopna;
12 : bval := VztTopeni;
13 : bval := Kotel;
14 : bval := HDO;
15 : bval := HJ306_1stupen;
// STRING
16 : IF VztBypass>=100 THEN sval:='1'; ELSE sval:='0'; END_IF;
17 : sval := VztMode;
END_CASE;
// nastav REAL jako STRING do array sensors
processValue := true;
CASE i OF
1..8 :
// zamezeni neustále zmenì hodnot senzoru (I. radek), vysledek je II. radek
// -99->22.1->22.1->22.2->22.1->22.2->22.3->22.2->22.3->22.3
// 22.1-> 22.15-> 22.25
// pokud doilo ke zmene
IF tempsensors[i] <> rval AND abs(tempsensors[i]- rval)>0.05 THEN
IF tempsensors[i] = -99 THEN
tempsensors[i] := rval;
ELSE
preRval := tempsensors[i];
tempsensors[i] := rval; // jako predchozi hodnotu pouzij neupravenou hodnotu
//namisto aktualni hodnoty dej prumer predchozi a nove hodnoty
rval := (rval + preRval)/2;
END_IF;
sensors[i].val := REAL_TO_STRINGF(rval,'%.1f');
ELSE
// neni zmena
processValue := false;
END_IF;
9..15 : sensors[i].val := BOOL_TO_STRING(bval);
16..17 : sensors[i].val := sval;
END_CASE;
//dataPub := DT_TO_STRING(GetRTC());
IF processValue and sensors[i].val<>sensors[i].preVal THEN
topicPub := sensors[i].name;
dataPub := sensors[i].val;
MQTTPub.sendcom := true;
sent:= true;
END_IF;
END_IF; // not busy
END_IF; // connected_to_broker
(* IF MQTTSub.connected_to_broker THEN
MQTTSub.subRq := 1;
END_IF;
MQTTSub(chanCode := ETH1_UNI2,
brokerIP := STRING_TO_IPADR(brokerIPaddr),
brokerPort := remotePort,
localPort := localPortSub,
connect := connect,
//keepAlive := keepAliveSubs,
//keepAliveInterval := keepAliveIntervalSubs,
//pingInterval := pingInterval,
//connTimeOut := connTimeOutSubs,
comparam := comparamSub,
//loginName := loginName,
//loginPass := loginPass,
topicTxt := topicSub,
//subRq := subRqSub
);
IF MQTTSub.connected_to_broker and MQTTSub.dataRec THEN
// doplnit co udelat po restartu ha - nic, broker posle klientovi ha znovu vsechny retain
// po restartu foxtrotu?
// Detekovat vypadek brokera: foxtrot by mel publikovat aktualni cas kazdou vterinu.
// https://community.home-assistant.io/t/alarm-if-mqtt-broker-goes-down/188826/5
// nenu­ potreba, mosquitto lze nastavit pro zachovani retain pri startu
// autosave_interval 1, autosave_on_changes true, persistence true, persistence_location /temp/
// TODO: zajistit, aby foxtrot opakoval poslani zpravy dokud neni potvrzeno prijeti
END_IF;
*)
END_PROGRAM
@kulheimzb
Copy link
Author

kulheimzb commented Oct 22, 2024

CP1000 limitations:

  • no https
  • no dynamic creation of communication channels, ETH_UNI is static (TCP client 512), one for publisher, second for subscriber

Kvůli tomuto omezení rozjet pouze publisher. Aby fungoval zároveň publisher i subscriber v Foxtrot1, tak každý musí mít dedikovaný ETH_UNI, který nesmí být použitý jinde v programu. (Ve Foxtrot2 lze již komunikační kanál vytvořit programově).

Mqtt server Mosqitto:
listener 1883
autosave_interval 1
autosave_on_changes true
persistence true
persistence_location /temp/

@petrp75
Copy link

petrp75 commented Feb 6, 2025

Dobrý den, bude to fungovat i na TČ Acond?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment