Aurea 5 hybrid: interfaces met de buitenunit en thermostaat

Pagina: 1 2 Laatste
Acties:

  • WackoH
  • Registratie: November 2012
  • Laatst online: 26-11 22:38
Je maakt mooie stappen!

Excuus voor de bugs.
De eerst (- not ok wordt gelogd als de data wel ok is) zit waarschijnlijk ook in mijn code. Maar ik heb er verder geen last van.
Die tweede (de compute aanroep voor quickpid zit niet in loop(), speedstate blijft dan altijd 0) is wellicht ontstaan toen ik de code wat opschoonde om hier neer te zetten. Bij mij lijkt de QuickPID tenminste volgens verwachting te werken.

Het algoritme moet inderdaad niet te traag worden. Bij mij bleek vooral het schrijven naar het scherm veel tijd te kosten. Vandaar dat dat zo is opgesplitst (iedere cyclus weer een ander deel updaten). Ik heb nu een cyclustijd van 30~40 ms

De grote van de weerstand maakt niet veel uit. Is alleen om de stroom te begrenzen. Ik heb dezelfde weerstand naar mijn AtMega2560 board opgenomen. Dat board had ik nog liggen en kwam goed uit vanwege de 4 hardware UARTs.

Software serial zou moeten werken, want dat moet de huidige MCU in de controlbox (ATmega8) ook doen om zowel en 1200 baud verbinding naar de andere MCU, als naar WP (666 baud) of Opentherm te onderhouden. Ik heb het ook wel op een Diecimila gebruikt toen ik aan het testen was.

  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
Ik zit nu op 25ms met een 2560, maar dat is vooral omdat ik een statisch array bewerk op moment dat iets naar de OT MCU gestuurd moet worden. Die bewerk cyclus is trouwens best langzaam, die had ik eerst in de reguliere loop zitten, cyclustijd was toen 110ms.

150 liter RVS tapwater vat heb ik ook al, nu nog een 3wegklep, 2KW heater en temperatuursensor en iets om die boel aan te sturen. Moet 'm alleen nog wel even wrappen of spuiten want sprsun-goud is niet goed voor de WAF.

  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
Zie dat er nog 1 hele nare bug in zit: als thermostaat warmte vraagt maar water heeft die temperatuur al dan blijft de warmtepomp uit. Geen circulatie, helemaal niks.
Heb vanmorgen op de laatste 0,3 graden verhoging mogen toekijken hoe elke paar minuten de warmtepomp aan en uit ging.

Fix is simpel: als er warmtevraag is vanuit thermostaat is, dan speedsetpoint minimaal 1.

Ketel loste dat op met code1 en dom rondpompen zonder te stoken.

Edit:
Aangepast in de post met de code van gisteren.
Zojuist even getest, stroomverbruik op stand 1 is marginaal, zo'n 200W. De helft van dat verbruik ging voorheen al op aan de ouderwetse AC pomp in de CV ketel.

[ Voor 19% gewijzigd door _JGC_ op 23-09-2025 16:09 ]


  • WackoH
  • Registratie: November 2012
  • Laatst online: 26-11 22:38
_JGC_ schreef op dinsdag 23 september 2025 @ 11:13:
Zie dat er nog 1 hele nare bug in zit: als thermostaat warmte vraagt maar water heeft die temperatuur al dan blijft de warmtepomp uit. Geen circulatie, helemaal niks.
Bij mij speelt dit niet. Heb het even nagekeken:
De thermostaat staat op 20.5oC. De afgelopen 72 uur is de temperatuur binnen 0.4oC stabiel gebleven. De WP schakelt aan als de temperatuur naar 20.4oC gaat. Soms loopt de temperatuur op tot 20.7 en een enkele keer tot 20.8. Maar gemiddeld zal het iets van 20.55oC zijn.
Heb vanmorgen op de laatste 0,3 graden verhoging mogen toekijken hoe elke paar minuten de warmtepomp aan en uit ging.
Dit herken ik helemaal niet.
De verschillen zullen wel komen doordat mijn CV systeem anders in elkaar steekt (combinatie radiatoren en vloerverwarming) waardoor temperatuur tijdens het nadraaien van de pomp in buitenunit (~30s) al genoeg daalt.

Maar je oplossing om het setpoint op 1 te zetten als er warmtevraag is klinkt prima en maakt het geheel robuuster, want alleen de pomp aanzetten gaat niet voor zover ik weet.

  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
Ik heb 'm vanmorgen laten lopen. Thermostaat vraagt continu setpoint van 25 graden bij verwarmen van 20.0 naar 20.5. Setpoint wordt redelijk snel gehaald en daarna stijgt deze in 3 uur tijd langzaam door naar 30 graden.
Het halfje opstoken op stand 1 duurde 2,5 uur en thermostaat liet de warmtepomp doorstoken tot 20.7. Al die tijd was het aangenaam, het kille gevoel van vanmorgen was vrij snel weg.

Nu is dit nog geen maatstaf voor de winter, want thermostaat regelt nog heel conservatief en de heatboosters starten de fans pas op bij verschil van 4 graden tussen aanvoer en kamertemperatuur. Verder hangen er boven nog radiatoren die in de winter ook warmte vragen maar nu helemaal niet.

Ik merk wel dat ik dit veel fijner vind dan die ketel die er 2-4x per uur even een paar minuten 6KW in duwde. Ook veel fijner dan de originele regeling die direct naar 35 graden doorstookt en daar blijft hangen.

[ Voor 13% gewijzigd door _JGC_ op 24-09-2025 22:19 ]


  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
@WackoH Ik vermoed dat die dingen komen door verschillen in regeling. Ik kwam er vanmorgen achter dat de OT MCU helemaal niet luistert naar CH_ON en CH_OFF. Die geeft gewoon vrolijk het setpoint van de thermostaat door, dat is ook waarom de pomp met de iSense continu bleef draaien.

De DIYLESS bouwt bij <0,3 van de temperatuur verwijderd een setpoint op en zodra die >=20 graden wordt volgt een CH_ON. Vanmorgen heeft de warmtepomp volgens vraag van thermostaat van 6:55 tot 8:15 gestookt, om 8:35 ging deze vrolijk tot 11:00 op laagste stand draaien en thermostaat heeft nooit wat gevraagd :X. Setpoint was al die tijd 12-13 graden ipv 10.

Algoritme nog maar iets aanpassen, ik wil wel doorstoken als setpoint geen 10 (uit) is, maar als setpoint van 10 (uit) af komt niet eerder stoken dan wanneer deze 20 wordt.

  • WackoH
  • Registratie: November 2012
  • Laatst online: 26-11 22:38
Zoals je het hier beschrijft en als ik naar het gedrag van de Anna kijkt, komt het inderdaad door de regeling.
Wat de Anna thermostaat doet, is de aanvraagtemperatuur op '0' houden als er geen warmtevraag is, en die snel laten stijgen als die er wel is. Dit ziet er dan zo uit:
Afbeeldingslocatie: https://tweakers.net/i/9gPEHQQc4mviSopWSq1LKVnXfWc=/fit-in/4000x4000/filters:no_upscale():strip_exif()/f/image/vJduySGftSiIzZtZZhMqJwpQ.png?f=user_large
Dus bij geen warmtevraag wordt het setpoint van aanvoertemperatuur van de WP ook naar snel beneden getrokken waardoor dat kort achter aan en uit schakelen wat jij zag, wordt vermeden.

Verder geeft de controlbox de aanvoertemperatuur naar de ketel 1-op-1 door, maar schaalt deze temperatuur als de WP warmte moet leveren.
Bv. 30oC aanvoer wordt setpoint 25oC voor de WP, en 60 wordt 40oC.
Dit concept heb ik overgenomen om de WP aan te sturen, maar ik weet eerlijk niet of het bij de ketel goed gaat. Die heb ik sinds begin dit jaar niet meer aan gehad :P

  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
Inmiddels de code wat aangepast. Dingen waar ik tegenaan liep:
- afrondingsverschillen vanwege floats, thermostaat geeft 20 graden setpoint, maar 20 >= 20 is niet altijd true, dus ging de regeling pas stoken bij 21 graden setpoint.
- nogal agressieve regeling. Van laag vermogen direct naar hoogste en daar dan 7 minuten op blijven draaien (hallo buurman)

Wat ik heb aangepast:
- stappenmodulatie, elke 120 seconden mag de regeling 1 stap omhoog of 1 stap omlaag.
- Uit als setpoint onder 15 komt na een stooksessie (float afronding zal me hier een zorg zijn)
- Aan als setpoint 19 of hoger wordt (uint8_t ipv float nu)
- Schakelen tussen trage en snelle regeling eruit
code:
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
/* 
Alternative control for the Atlantic Aurea heat pump, which based on the Chofu AEYC-0643XU-AT unit.
This is a sketch to control the power setting of a heat pump with an Arduino ATMega2560 and to modify communication inside the controlbox using 3 of the 4 hardware serial ports of this board. 
The original code shows various useful information like temperatures etc. on a 480*320 TFT LCD. This has been removed here to keep the code more compact.
Version 0.1Beta, JHN 19-03-2025
*/

#include <QuickPID.h>                                   // Library for PID controller, see for documentation: https://github.com/Dlloydev/QuickPID

//Define variables and constants
// General
String MessageString = "";

  // For heat pump
const uint8_t SpeedStages = 6;                        // Number of speed stages to be used (7 --> ~1400 W max)
uint8_t SpeedSetpoint = 0;                            // Speed setpoint sent to heatpump
uint8_t SpeedSetpointOld = 0;
uint8_t TargetTemperatureThermostat = 20;             // Target temperature as requested by the thermostat
const float MinTemp4HP = -15;                         // Outside temperatute below wich heat pump should stop working and CV should start
uint16_t TelegramCount = 0;                           // Follow-up number of telegrams
// Variables to track timings
uint32_t Interval = 0;                                // Time since last telegram
uint32_t currentMillis = 0;                           // Check timing for sending messages
uint32_t LastSpeedSetpointChange = 0;                 // Keep track when last time speedsetpint has been changed in milliseconds
uint32_t SpeedSetpointHysteresis = 120000;            // Allow a change in speedsetpoint only once per 2 minutes (when using slow PID parameter set)
// Cycle time check
uint32_t previousCycleMicros = 0;                     // To store the time of the last cycle start
uint32_t currentCycleMicros = 0;                      // To store the time of the current cycle start
uint32_t cycleTime = 0;                               // To store the calculated cycle time
uint16_t cycleCounter = 0;                            // Counter to track cycles
const uint16_t displayInterval = 10000;               // Display cycle time every 10000 cycles
uint8_t lcdUpdateStep = 0;                            // Variable to spread writing to screen over multiple steps
// Receive and send inter MCU data 
const uint32_t McuMessageWaitTime = 200;              // Waiting time between receiving message on Pad 1 (Serial 1) and sending on pad 2 (serial 2) in ms
uint32_t McuMessageOneReceived = 0;                   // Tie last message send in ms
bool dataMcu2Send = false;
uint32_t PreviousMessageSerial1Sent = 0;   
uint32_t MessageSerial1Interval = 4200;              // Maximum interval for sending message on serial 2 (to avoid that communication stops)
const uint8_t DataMcuLength = 12;                     // Length of each transmission between MCU's
uint8_t dataArrayOT_IC1_IC2[DataMcuLength] = {32,20,154,0,0,0,0,32,29,7,0,18};     // Array to store the incoming 12 bytes for OT IC1 to IC2.
uint8_t dataArrayOT_IC2_IC1[DataMcuLength] = {0};     // Array to store the incoming 12 bytes for OT IC2 to IC1. 
uint16_t ChecksumMCU = 0;                             // Checksum for communication between MCU's
// Variables for communication with heat pump
uint8_t CB_HPlength = 0;                              // Length of communcation CB to HP
uint16_t ChecksumCBHP = 0;                            // Checksum for communication of heat pump with control box
uint8_t ChecksumCBHPfalseCount = 0;                   // Counter for number of times that the checksum did not match. After certain number of mismatches, message will be send to the serial port
uint8_t data0[] = { 0x19, 0x0, 0x8, 0x0, 0x0, 0x0, 0xd9, 0xb5 };                       // Array of hexadecimal bytes
uint8_t data1[] = { 0x19, 0x1, 0x0c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xaa, 0x35 };  // Array of hexadecimal bytes
uint8_t data2[] = { 0x19, 0x2, 0x8, 0x1, 0x1, 0x0, 0x99, 0x37 };                       // Array of hexadecimal bytes. This is the one to change bytes 4 (on/off) and 5 (setpoint), and 7 and 8 (high and low bytes of the CRC CCITT checksum)
uint8_t data3[] = { 0x19, 0x3, 0x8, 0xb2, 0x2, 0x0, 0xc1, 0x9a };                      // Array of hexadecimal bytes

// Variables for sending messages to heat pump
bool IncomingMessageEnded = false;                      // Last message start time in milliseconds
volatile uint32_t PreviousMessageSent = 0;              // Time when prveious message was sent in milliseconds
volatile bool IsReceiving = false;                      // Tracks if message is being received from heat pump to block sending next message to heat pump
const uint32_t SendTimeout = 2000;                      // Time in milliseconds to wait before considering the communication ended
const uint32_t SendDelay = 99;                          // Delay in milliseconds before sending information to heatpump
const uint32_t MinMessageSendInterval  = 300;           // Minimum interval in millis between sending messages when no reply is received
volatile uint32_t previousMessageInEnded = 0;

// Definitions for reading and checking heat pump data
// Prepare array for storing data from heatpump
const uint8_t StartByte = 0x91;                     // First byte must be 145 (0x91)
const uint8_t Rows = 4;                            // Number of rows in heat pump data array 
const uint8_t Cols = 80;                            // Number of columns in heat pump data array 
uint8_t numChars = 0;                               // Number of characters to be written to screen
uint8_t dataHeatPumpTemp[Cols][Rows] = {0};         // Array to store of four messages from heatpump before checksum check
uint8_t dataHeatPump[Cols][Rows] = {0};             // Array to store of four messages from heatpump after checksum is correct
uint8_t dataHeatPumpOld[Cols][Rows] = {0};          // Array to store previous data of four messages so that screen is only updayted when needed
uint8_t extractedRow[Cols];                         // 1D array to store the row  
const uint8_t ValidLengths[] = {13, 14, 19, 21};    // Lengths 12, 13, 18 & 20   (12+1), (13+1), (18+1), (20+1)
uint16_t value;                                     // Temporarily storage of datapoint from array
float valuefloat;
uint8_t Length = 0;
float T_supply =0;                                  // Supply water temperature by heatpump
float T_return =0;                                  // Return water temperature to heatpump
float T_outside =0;                                 // Outside temperature measured on heatpump
// State variables for non-blocking serial reading
enum SerialState {  Wait_Start,                     // Waiting for the start of a serial message  
                    Read_Header,                    // Reading the header of the message  
                    Read_Payload,                   // Reading the main data (payload)  
                    Read_End                        // Reading the end of the message  
                  };                              // Enumeration type, which helps in defining different states of serial communication
SerialState state = Wait_Start;                     // Make waiting to start the default
uint8_t ID = 0;
uint8_t msgLength = 0;
uint8_t DataLength = 0;
uint8_t buffer[Cols] = {0};                         // Temporary buffer for incoming data
uint8_t index = 0;
int8_t NegT = 0;                                    // Store if temperature is negative (value of 255 in MSB)
// For PID controller 
float TemperaturePIDsetpoint = 0;                  // Desired supply temperature
uint8_t TemperaturePIDsetpointOld = 0;
const float TemperaturePIDsetpointMax = 37;         // Maximum temperature setpoint
const float TemperaturePIDsetpointMin = 25;         // Maximum temperature setpoint
const float TemperaturePIDsetpointOff = 15;
const uint8_t TemperaturePIDsetpointMinStart = 19;
float TemperaturePIDinput = 0;                      // Current suppy temperature (feedback from the sensor in the heatpump)
float TemperaturePIDoutput = 0;                     // Heat pump control signal
float TemperaturePIDoutputRounded = 0;              // Heater control signal, rounded off
// PID tuning parameter. Default values were Kp = 2.0, Ki = 5.0, Kd = 1.0
const float Kp0 = 0.02, Ki0 = 0.008, Kd0 = 0.01;// 
float Kp = Kp0, Ki = Ki0, Kd = Kd0;// 
// Create PID object
QuickPID myPID(&TemperaturePIDinput, &TemperaturePIDoutput, &TemperaturePIDsetpoint, Kp, Ki, Kd, /* OPTIONS */
                myPID.pMode::pOnError,                   /* pOnError, pOnMeas, pOnErrorMeas */
                myPID.dMode::dOnMeas,                    /* dOnError, dOnMeas */
                myPID.iAwMode::iAwCondition,             /* iAwCondition, iAwClamp, iAwOff */
                myPID.Action::direct);                   /* direct, reverse */

void setup() {
  // Serial Setup
  Serial.begin(115200);                                   // Start the Serial Monitor for debugging on terminal (Serial port 0)
  Serial3.begin(9600);                                    // Start serial port 1 for receiving messages from OT MCU to HP MCU (RX3, 9600 bps)
  Serial1.begin(666);                                     // Start serial port 3 for sending an receiving info to heat pump at 666 baud (RX1 and TX1)
  Serial3.setTimeout(100);                                // Changes the timeout for readBytes() and other blocking serial read functions (readString(), readBytesUntil(), etc.).
  // For QuickPID
  myPID.SetOutputLimits(0, 99);                           // Set to max 99% to have max. 4 digits ('99.9')
  myPID.SetSampleTimeUs(5000000);                         // Sample time of PID controller in microseconds. Made slower than default because of relatively slow temperature changes and heat pump response to save processing time.
  myPID.SetTunings(Kp, Ki, Kd);
  myPID.SetMode(myPID.Control::automatic);                // Set PID controller in automatic, i.e. input (PV) is perdiodically compared with setpoint (SP) and control variable (CV) is adjusted 

  delay(5000);
  Serial.println("Setup complete.");
}

//////////////// Main loop ////////////
void loop() {
  currentMillis = millis();                                 // get curent millis (ms) for sending message to heat pump
  currentCycleMicros = micros();                            // Capture the current time (in us) to calculate the cycle time of the loop
  cycleCounter++;                                           // Increment the cycle counter
  
  // Check for incoming data on Serial 1 (Pad 1 from MCU 2), 2 (Pad 2 from MCU 1) and Serial 3 (data from heat pump)
  readSerialMessageHP();                                      // Call this function continuously to check for data on the incoming serial port from the heat pump
  if (Serial3.available() >= DataMcuLength) {                 // Check whether the serial buffer connected to Pad 1 contains DataMcuLength (12) bytes or more  
    readSerialMessageMCU(1);                                  // When so, jump to subroutine to read the bytes or clear the buffer
    TemperaturePIDsetpoint = dataArrayOT_IC2_IC1[0];
    if (TemperaturePIDsetpoint > TemperaturePIDsetpointMax){
      TemperaturePIDsetpoint = TemperaturePIDsetpointMax;
    } else if (TemperaturePIDsetpoint <= TemperaturePIDsetpointOff || (TemperaturePIDsetpointOld == 0 && round(TemperaturePIDsetpoint) < TemperaturePIDsetpointMinStart)) {
      TemperaturePIDsetpoint = 0;
    } else if (TemperaturePIDsetpoint < TemperaturePIDsetpointMin) {
      TemperaturePIDsetpoint = TemperaturePIDsetpointMin;
    }
    TemperaturePIDsetpointOld = round(TemperaturePIDsetpoint);
  }

  
  // Write modified message from MCU 1 to 2 on serial 2
  if ((currentMillis-PreviousMessageSerial1Sent) > MessageSerial1Interval)  {
    readSerialMessageMCU(2);
    Serial3.write(dataArrayOT_IC1_IC2, sizeof(dataArrayOT_IC1_IC2));    // Write array to serial port 2
    PreviousMessageSerial1Sent = currentMillis;
  }
  

  // Send the next message to the heat pump 100 ms after the previous incoming message has ended, or after 1000 ms without sending anything. Use the periodic sending also to update the screen
  currentMillis = millis();                                 // get curent millis (ms) for sending message to heat pump
  if ((( (currentMillis - previousMessageInEnded >= SendDelay)  &&  (!IsReceiving))  || ( currentMillis - previousMessageInEnded >= SendTimeout )) && (currentMillis - PreviousMessageSent >= ( MinMessageSendInterval ))) 
  {
    switch (TelegramCount) {
      case 0:
        Serial1.write(data0, sizeof(data0));
        break;
      case 1:
        Serial1.write(data1, sizeof(data1));
        break;
      case 2:
        SpeedSetpoint = (int)round( TemperaturePIDoutput / (100 / SpeedStages )) ;    // Scale the PID controller output from 0~100% to 0~8 speed setpoints, and convert from double to rounded integer
        if (SpeedSetpoint == 0 && TemperaturePIDsetpoint > 0) {
          // Workaround: We still want heat, but not much. Keep WP running
          SpeedSetpoint = 1;
        }
        if (SpeedSetpoint == 0) {
          data2[3] = 0x0;
          data2[4] = 0x0;
          SpeedSetpointOld = 0;
        } else if (SpeedSetpointOld != SpeedSetpoint && (currentMillis - LastSpeedSetpointChange > SpeedSetpointHysteresis)) {
          if (SpeedSetpoint > SpeedSetpointOld) {
            SpeedSetpoint = SpeedSetpointOld+1;
          } else {
            SpeedSetpoint = SpeedSetpointOld-1;
          }
          data2[3] = 0x1;
          data2[4] = SpeedSetpoint;                 // Write calculate speed setpoint in array  
          LastSpeedSetpointChange = currentMillis;
          SpeedSetpointOld = SpeedSetpoint;
        }
         
        CB_HPlength = sizeof(data2);
        calculate_CRC_CCITT_Checksum(data2, CB_HPlength-2, &ChecksumCBHP);  
        data2[6] = (ChecksumCBHP >> 8) & 0xFF;          // Replace byte 6 with checksum High Byte
        data2[7] = ChecksumCBHP & 0xFF;                 // Replace byte 7 with checksum Low Byte
        Serial1.write(data2, sizeof(data2));
        break;
      case 3:
        Serial1.write(data3, sizeof(data3));
        break;
      default:
        Serial.print("Invalid TelegramCount value:  ");Serial.println(TelegramCount); 
        break;
    }
    TelegramCount = (TelegramCount + 1) % 4;          // Cycle through 0-3
    PreviousMessageSent = millis();
  }

  if (cycleCounter >= displayInterval) {
    if (previousCycleMicros != 0) {
      cycleTime = ( currentCycleMicros - previousCycleMicros ) / displayInterval;  // Time difference between cycles
      previousCycleMicros = currentCycleMicros;           // Update the previous cycle time
      cycleCounter = 0;                                   // Reset the cycle counter
    } else {
      previousCycleMicros = currentCycleMicros;
    }
  
    switch (lcdUpdateStep) {
      case 0:                                             // Print the cycle time etc. The timing for sneding message to the heatpump wil be oof when the cycle time is too long (> ~50 ms)
        Serial.println("Cycle time "+String(cycleTime)+" ms");
        break;
      case 1:                                             // Print PID settings
        break;
      case 2:                                             // Compresor speed 91-3,9
        if (dataHeatPump[9][3] != dataHeatPumpOld[9][3]) {  // Data has changed?
          Serial.print("Speed setpoint: "); Serial.println(dataHeatPump[9][3]);
          dataHeatPumpOld[9][3] = dataHeatPump[9][3];
          }
        break;
      case 3:                                             // Compresor power 91-3,10
        if (dataHeatPump[10][3] != dataHeatPumpOld[10][3]) {
          MessageString = String((25.6 * dataHeatPump[10][3]),0);
          Serial.print("Compressor power: "); Serial.println(MessageString);
          dataHeatPumpOld[10][3] = dataHeatPump[10][3];
        }
        // Compressor mode 91-1,3
        if (dataHeatPump[3][1] != dataHeatPumpOld[3][1]) {
          Serial.print("Compressor mode: "); Serial.println(dataHeatPump[3][1]);
          dataHeatPumpOld[3][1] = dataHeatPump[3][1];
        }
        // Defrost?   91-1,4
        if (dataHeatPump[4][1] != dataHeatPumpOld[4][1]) {
          Serial.print("Defrost ongoing? "); Serial.println(dataHeatPump[4][1]);
          dataHeatPumpOld[4][1] = dataHeatPump[4][1];
        }
        break;
      case 4:
        // ?Data? 91-3,5
        if (dataHeatPump[5][3] != dataHeatPumpOld[5][3]) {
          Serial.print("Generic info "); Serial.println(dataHeatPump[5][3]);
          dataHeatPumpOld[5][3] = dataHeatPump[5][3];
        } 
        break;
      case 5:                                             // Temperatures
        // Supply temperature   91-2,3~4
        if (dataHeatPump[3][2] != dataHeatPumpOld[3][2]) {
          value = dataHeatPump[4][2];                             // MSB of temperature; previous byte is the MSB
          T_supply = (((value*256+dataHeatPump[3][2])-(65536*((value == 255) ? 1 : 0)))/10.0);  // Do the conversion to temperature in such a way that also negative temperature can be shown
          TemperaturePIDinput = T_supply;                       // Make the input the PID controller equal to the current supply water temperature   
          MessageString = String(T_supply,1);
          Serial.print("Supply temperature "); Serial.println(MessageString);
          dataHeatPumpOld[3][2] = dataHeatPump[3][2];
        }
        // Return temperature 91-2,5~6
        if (dataHeatPump[5][2] != dataHeatPumpOld[5][2]) {
          value = dataHeatPump[6][2];               // MSB of temperature; previous byte is the MSB
          T_return = (((value*256+dataHeatPump[5][2])-(65536*((value == 255) ? 1 : 0)))/10.0);  // Do the conversion to temperature in such a way that also negative temperature can be shown
          MessageString = String(T_return,1);
          Serial.print("Return temperature "); Serial.println(MessageString);
          dataHeatPumpOld[5][2] = dataHeatPump[5][2];
        }
        break;
      case 6:
        // Outside temperature 282 91-2,7~8
        if (dataHeatPump[7][2] != dataHeatPumpOld[7][2]) {  
          value = dataHeatPump[8][2];               // MSB of temperature; previous byte is the MSB
          T_outside = (((value*256+dataHeatPump[7][2])-(65536*((value == 255) ? 1 : 0)))/10.0);  // Do the conversion to temperature in such a way that also negative temperature can be shown
          MessageString = String(T_outside,1);
          Serial.print("Outside temperature "); Serial.println(MessageString);
          dataHeatPumpOld[7][2] = dataHeatPump[7][2];
        }
        break;
      case 7:                                             // Do PID calculation
        break;
      case 8:                                             // Print inter MCU communication 
        break;
      case 9:
        TemperaturePIDoutputRounded = round(TemperaturePIDoutput*10.0)/10.0;
    }
    lcdUpdateStep = (lcdUpdateStep + 1) % 10;  // Cycle through screen updates
  }
  myPID.Compute();
}////////////// End of main loop  //////////////////////////

////////  Below are the subroutines //////////////////////
void readSerialMessageMCU(uint8_t MCU) {
  uint8_t TempMcuData[DataMcuLength] = {0};
  uint8_t TemperatureCategory;  // Variable to categorize temperature
  ////// Inter MCU communication
  switch (MCU) {
    case 1:          // 1. Communication IC2 (OT) to IC1 (HP): This communication is via PAD 1 and therefore used at serial 1. Check if enough data has arrived in the serial buffer and read it
      Serial3.readBytes(TempMcuData, DataMcuLength);        // Clean way of reading fixed number of bytes into array. Beware: Blocks execution until all bytes arrive or timeout (default timeout is 1000ms).
      calculateMCUChecksum(TempMcuData, DataMcuLength, ChecksumMCU);// Calculate and check the checksum by determining the sum of the first 11 bytes and taken modules 256
      if (ChecksumMCU == TempMcuData[DataMcuLength-1]) { // Check if the checksum matches
        memcpy(dataArrayOT_IC2_IC1, TempMcuData, DataMcuLength); // Checksum OK so copy temp array to permanent array, cleaner and faster code than a loop  
        ChecksumMCU = false;                                // Make checksum false as start value for next time
        McuMessageOneReceived = currentMillis;

      } else {                                            // Checksum incorrect because communication possibly halfway received. 
        clearSerialBuffer(Serial3);                     // Clears the read buffer of serial 1 if the checksu was wrong to make a fresh start
        Serial.println("Serial buffer 1 cleared");
      }
      break;
    case 2:         // 2. Communication IC1 (HP) to IC2 (OT): This communication is via PAD 2 and therefore used at serial 2. Check if enough data has arrived in the serial buffer, read it, modify when required and resend
      //Serial1.readBytes(TempMcuData, DataMcuLength);      // Clean way of reading fixed number of bytes into array. Beware: Blocks execution until all bytes arrive or timeout (default timeout is 1000ms).
      //calculateMCUChecksum(TempMcuData, DataMcuLength, ChecksumMCU);// Calculate and check the checksum by determining the sum of the first 11 bytes and taken modules 256                            // Make checksum false as start value for next time
      if (T_outside < MinTemp4HP) {
        TemperatureCategory = 0;                             // Too cold for heat pump, switch on cental heating
      } else if (T_outside < 4) {
        TemperatureCategory = 1;  // Below 4°C             // Prevent that controlbox starts CV 
      } else if (SpeedSetpoint == 0) {
        TemperatureCategory = 2;                         // SpeedSetpoint is zero
      } else {
        TemperatureCategory = 3;                       // In all other cases use the temperature setpoint for water as read from Plugwise Anna via MCU2
      }                 
      switch (TemperatureCategory) {
        case 0:                                     // Heat pump is not running because it is too cold so central heating should be started
          dataArrayOT_IC1_IC2[0] = 0xf0;
          break;
        case 1:                                     // Below 4°C but heat pump can run, adjust values to prevent central heating activation
          dataArrayOT_IC1_IC2[0] = dataArrayOT_IC2_IC1[0];
          dataArrayOT_IC1_IC2[9] = 0x04;
          dataArrayOT_IC1_IC2[4] = 0;               // Write 0's to force MCU2 to transfer HP temperature to OpenTherm 
          dataArrayOT_IC1_IC2[5] = 0;
          dataArrayOT_IC1_IC2[6] = 0;
          dataArrayOT_IC1_IC2[10] = 0;
          break;
        case 2:                                     // Heat pump is not running (Speedsetpoint  is zero), then let central heating boiler temperatures go to OpenTherm
        case 3:                                     // In all other cases use the temperature setpoint for water as read from Plugwise Anna via MCU2
          dataArrayOT_IC1_IC2[0] = dataArrayOT_IC2_IC1[0];
          dataArrayOT_IC1_IC2[4] = 0;             // Write 0's to force MCU2 to transfer HP temperature to OpenTherm 
          dataArrayOT_IC1_IC2[5] = 0;
          dataArrayOT_IC1_IC2[6] = 0;
          dataArrayOT_IC1_IC2[10] = 0; 
          break;
      }
      dataArrayOT_IC1_IC2[7] = round(T_supply);
      dataArrayOT_IC1_IC2[8] = round(T_return);
      if (T_outside >= 4) {
        dataArrayOT_IC1_IC2[9] = round(T_outside);
      }
      calculateMCUChecksum(dataArrayOT_IC1_IC2, DataMcuLength, ChecksumMCU);// Recalculate the checksum
      dataArrayOT_IC1_IC2[11] = round(ChecksumMCU); // Replace old checksum value with new calculated one
      break;
  }
}

void clearSerialBuffer(HardwareSerial &serialPort) {  
  while (serialPort.available() > 0) {
    serialPort.read();                                  // Read and discard the data in the buffer
  }
}

void calculateMCUChecksum(uint8_t dataArray[], int Length, unsigned int &checksum) {  // Calculate the checksum by determining the sum of the first 11 bytes and then take modules 256
  checksum = 0; // Initialize the checksum
  if (Length <= 1) {    // Ensure length is valid
    checksum = 0;
    return;
  }
  // Calculate the checksum for the first (Length-1) bytes in the specified row
  for (int i = 0; i < Length - 1; i++) {
    checksum += dataArray[i];
  }
  checksum %= 256;                                        // Modulus 256 to keep it in a single byte
}

// Function to calculate the CRC-CCITT (0xFFFF) checksum for the communication to and from the heat pump
void calculate_CRC_CCITT_Checksum(uint8_t *data, uint8_t Length, uint16_t *checksum) {
  uint16_t crc = 0xFFFF; // Initial value
  for (uint8_t i = 0; i < Length; i++) {
    crc ^= (uint16_t)data[i] << 8;
    for (uint8_t j = 0; j < 8; j++) {
      if (crc & 0x8000) {
        crc = (crc << 1) ^ 0x1021;
      } else {
        crc <<= 1;
      }
    }
  }
  *checksum = crc;
}

// Function that reads the serial data coming from the heat pump
void readSerialMessageHP() {
  while (Serial1.available()) {  // Check if data is available on Serial1
    IsReceiving = true;
    uint8_t byteReceived = Serial1.read();
    IsReceiving = true;
    switch (state) {
      case Wait_Start:                            // Code to wait for the start character
        if (byteReceived == StartByte) {
          state = Read_Header;
          index = 0;
          IncomingMessageEnded = false; // Reset if any other byte is received to indicate
        }
        break;
      case Read_Header:                           // Code to process header bytes
        if (index == 0) {
          ID = byteReceived;
          if (ID > 3) {  // ID must be 0-3
            Serial.println("Invalid ID, resetting...");
            state = Wait_Start;
            return;
          }
        } else if (index == 1) {
          msgLength = byteReceived+1;
          if (!IsValidLength(msgLength)) {
            Serial.println("Invalid Length! Resetting...");
            state = Wait_Start;  // Reset
            return;
          }
          DataLength = msgLength - 3;  // Exclude first 3 bytes and last byte
          index = 0;
          state = Read_Payload;
        }
        index++;
        break;

      case Read_Payload:                          // Code to process data payload
        buffer[index++] = byteReceived;
        if (index >= DataLength) {
          state = Read_End;
        }
        break;

      case Read_End:                              // Code to check that last byte of message corresponds to '0'
        if (byteReceived == 0) {  // Ensure last byte is 0
          StoreMessage(ID, DataLength, buffer);
          IncomingMessageEnded = true;                          // If the end of the incoming message is reached, set the infication boolean
          previousMessageInEnded = millis();                    // Set timestamp after receiving end of incoming message             
        } else {
          Serial.println("Warning: Last byte is not 0! Resetting...");
        }
        IsReceiving = false;
        state = Wait_Start;                                     // Reset for next message
        break;
      default:
        Serial.println("Error in readSerialMessageHP state"); 
        break;
    }
  }
}

// Function to check if the Length is valid
bool IsValidLength(uint8_t Length) {
  for (uint8_t i = 0; i < sizeof(ValidLengths) / sizeof(ValidLengths[0]); i++) {
    if (Length == ValidLengths[i]) return true;
  }
  return false;
}

// Function to store messages in separate arrays based on ID
void StoreMessage(uint8_t ID, uint8_t DataLength, uint8_t *message) {
  for (uint8_t i = 0; i < (DataLength); i++) {
    dataHeatPumpTemp[i+2][ID] = message[i];
  }
  dataHeatPumpTemp[0][ID] = StartByte;
  dataHeatPumpTemp[1][ID] = ID;
  dataHeatPumpTemp[2][ID] = DataLength+2; // 12, 13, 18, 20
  for (int j = 0; j < DataLength+2; j++) {                                  // Copy row 
    extractedRow[j] = dataHeatPumpTemp[j][ID];  
  } 
  calculate_CRC_CCITT_Checksum(extractedRow, DataLength+2, &ChecksumCBHP);   // Calculate checksum, including the two checksum bytes --> result will be zero if mesage has been sent error free
  if (ChecksumCBHP == 0) {                                                   // Check that result is indeed zero
    memcpy(dataHeatPump[ID], dataHeatPumpTemp[ID], Cols * sizeof(uint8_t));  // Transfer the temporarily array to the permanent array
    ChecksumCBHPfalseCount = 0; 
  } else {
    ChecksumCBHPfalseCount++;                                              // Increase counter for false checksums. Nog actie bedebken als threshold wordt bereikt
    Serial.print("Checksum error! ");                                      // Print a message if there is an error
    Serial.print("Now ");Serial.print(ChecksumCBHPfalseCount);Serial.print(" Checksum errors (of max 10) counted!");
  }
}

[ Voor 0% gewijzigd door _JGC_ op 04-10-2025 15:52 . Reden: code aanpassingen ]


  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
@WackoH Ik lees hier eerder in het topic dat de warmtepomp niet op stand 1 wil draaien op kou. Wat gaat deze doen dan? Gaat de warmtepomp dan steeds uit, of krijg je stand 2?

Nieuwe regeling lijkt hier de temperatuur niet meer door te geven aan de thermostaat, dus heb nog een bug ergens. Lampje op de schakelaar brandt vanmorgen ook ineens dus lijkt erop dat de OT MCU denkt dat de ketel stookt.

Edit: inmiddels achterhaald. Lijkt erop dat ik de seriele poort van mijn Mega gesloopt heb of de bedrading slecht contact maakt, ik krijg niks meer door van de OT MCU. Gek genoeg kreeg ik dat nog wel éénmalig na het flashen van de oude code, maar inmiddels ook niet meer.

Edit2: seriele poorten omgedraaid en werkt weer. Poort dus niet kapot maar speling op de prikkabeltjes.
Ik overweeg sterk om de OT MCU gewoon dood te zwijgen en een ESP8266 te gebruiken met een OT Slave bord erop. Huidige code gooit de setpoint naar 0.0 bij een communicatiefout, dat heb ik vanmorgen kunnen zien in de aanvoertemperaturen van de heatboosters. Ik dacht aan defrosts (koud en veel regen), maar ding heeft vanmorgen vroeg een hele tijd staan knipperen tussen aan en uit.

[ Voor 51% gewijzigd door _JGC_ op 04-10-2025 14:07 ]


  • WackoH
  • Registratie: November 2012
  • Laatst online: 26-11 22:38
De buitenunit gaat gewoon aan als je stand 1 stuurt. Volgens mij bepaalt dit de snelheid van de compressor (vandaar dat ik het 'speed stage' en niet 'power stage' heb genoemd). Welk vermogen dan wordt opgenomen hangt vermoedelijk primair af van de gasdrukken in de buitenunit. En die hangen weer af van o.a. de buiten-, aan- en afvoertemperatuur (denk ik, ben geen airco specialist). Dit blijkt bv. hieruit:
Afbeeldingslocatie: https://tweakers.net/i/IpOqcsI6VogP6lo_hi8vzIQLM2A=/fit-in/4000x4000/filters:no_upscale():strip_exif()/f/image/5ULZTFL5AZgdBCExsAu9xPnw.png?f=user_large

Het beste wat ik heb kunnen doen is met een Arduino steeds een hogere stand vragen, en dan met een externe meter het opgenomen vermogen bepalen:
Afbeeldingslocatie: https://tweakers.net/i/_fWXMFifsYaMO3xcZ1XEE6JDs1w=/fit-in/4000x4000/filters:no_upscale():strip_exif()/f/image/OF7RT2dEkjJ6ldb2drOQGUGm.png?f=user_large
Mijn conclusie was dat er 12 standen (plus 'uit') zijn Maar er zijn ook condities dat de WP niet meer vermogen op gaat nemen bij de hoogste standen. Dan zit 'ie blijkbaar al eerder aan z'n max. Sowieso is het beter niet op max vermogen te draaien want dan zakt de COP in. Atlantic geeft slechts 1.1 kW als max. vermogen met een COP van 4.63 bij A7W35. In een Chofu service manual staat een COP van 4.20 bij 1.43 kW. Wellicht heeft Atlantic het vermogen begrensd om in een hogere subsidie-categorie te vallen.

Daarom heb ik het aantal standen in mijn programma tot slechts 7 beperkt. Daarmee wordt het opgenomen vermogen in de praktijk max. ~1400W. Dit voldeed om het huis gedurende de afgelopen winter zonder CV warm te houden.

Zoals ik het heb opgebouwd is relatief complex. Met de kennis van nu zou ik bv. een ESP32 (heeft twee complete hardware UARTS vrij, de ESP8266 is wat kreupel op dat vlak) nemen en die zeker de HP, en misschien zelfs de OT communicatie laten doen, en dan via WiFi met Home Assistant verbinden om data uit te lezen.

Ik heb er zelfs eentje liggen met scherm en al. Maar ja, ik heb nu de volledige Plugwise functionaliteit (incl. Home Assistant integratie), de temperatuur in de woonkamer blijft prima stabiel, en bovenal draait het probleemloos. Dus ik zou er niets op vooruit gaan.

[ Voor 5% gewijzigd door WackoH op 04-10-2025 22:19 ]


  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
Heb hier de sturing nu enige tijd draaien. Verwarmt goed en relatief snel, maar merkte dat in de ochtend of bij een half graadje meer de regeling net even wat te agressief is. Thermostaat stuurt bij verhoging meteen op 35 graden setpoint, sturing rekent uit dat 27 graden verschil met de buitentemperatuur wel heel veel is en gaat meteen vol gas. Gevolg is deltaT van 10-12 graden en een rammelende compressor en een buurman die het in huis hoort (vanmorgen sms van hem dat hij het best wel vervelend vond).

Dan ben je blij met fatsoenlijke isolatie, nu de regeling tot speedstep 5 beperkt en de aanvoertemperatuur beperken op 5 graden boven retour (hier is de deltaT 2-3 graden bij lang draaien op laagste vermogen).

  • P1 modubus
  • Registratie: Maart 2023
  • Laatst online: 11:47
Goedendag allemaal,
hier een update van mij, ik heb alleen de buitentemperatuur 6-7 grd hoger als werkelijk in schakelbaar gemaakt, om stroom te sparen, de circulatiepomp gaat dan pas draaien als het echt vriest, normaal <5grd C,
nu bij -1 grd., de WP blijft ook langer in bedrijf, hoelang zullen we spoedig zien.
De deltaT blijft ook mooi rond de 5- 6 grd.C
CV Ketel is niet aangesloten op de WP regeling, deze kan ik wel separaat inschakelen mocht het nodig zijn.
Ben nu nog tevreden, stook meestal middags vanaf 13.00 uur tot 20.00 uur wel tot 22 grd in de huiskamer,
Morgens is de dan nog 20.5 grd tot aan de middag 20.0 grd. C tot nu toe..
Zie plaatjes de gewenste watertemperatuur wordt niet gehaald maar is nu perfect voor ons de ruimtetemperatuur stijgt langzaam eigenlijk nog te snel maar om de zonnen energie te gebruiken is dit wel ideaal, al is het een leerproces voor volgend jaar.
Afbeeldingslocatie: https://tweakers.net/i/bpnWRolArdSjVce3AzMTy6vpRgo=/800x/filters:strip_icc():strip_exif()/f/image/axQNj4czDKtMrLKXU9vbYzir.jpg?f=fotoalbum_large

Afbeeldingslocatie: https://tweakers.net/i/4AJQwE8mOAv09wORa6Jne6UUu38=/800x/filters:strip_icc():strip_exif()/f/image/foP1iqIAydLpSLYSGYowW43R.jpg?f=fotoalbum_large

Op het WebVision plaatje staat het rendement van 459% berekend uit het opgenomen vermogen en het afgegeven vermogen, de opgenomen energie, zijn de gegevens op het plaatje in de warmtepomp zelf Amp, en Watt, de afgegeven energie, deze zijn berekend uit de gegevens onder de ketel, toevoertemperatuur, retourtemperatuur en stroming..
De temperatuur boven de WP vermeld is de buiten temperatuur.

Gelukkig werkt het nu, ben niet zo goed met software schrijven, wel inmiddels een Arduino une en Raspberry PI 4 en 5 aangeschaft om me toch voor te bereiden, hopelijk is het niet nodig, een studie apart merk ik wel,
wel zeer interessant, wil de temperatuursverwachting mee laten wegen in het stook gedrag van HVAC regeling, weet natuurlijk niet wat het wordt maar dat zie ik wel,

Tot kouder weer.

  • P1 modubus
  • Registratie: Maart 2023
  • Laatst online: 11:47
JGC schreef
Gevolg is deltaT van 10-12 graden en een rammelende compressor en een buurman die het in huis hoort (vanmorgen sms van hem dat hij het best wel vervelend vond).


Het is belangrijk dat het hydraulisch goed in me kaar zit, welke watertemperatuur ook gevraagd wordt, de Dt moet binnen de beperken blijven ook met 100% vermogen, zorg eerst dat de bypass goed ingeregeld wordt, daarna kun je verder, kijk maar naar mijn Dt en stookgedrag van de WP, buurman en jij zullen dan ook blij zijn geen overmatig geluid meer.

Ps. weet niet hoe ik een reactie moet plaatsen, dus nu maar zo.
Succes

  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
P1 modubus schreef op maandag 17 november 2025 @ 20:56:
JGC schreef
Gevolg is deltaT van 10-12 graden en een rammelende compressor en een buurman die het in huis hoort (vanmorgen sms van hem dat hij het best wel vervelend vond).


Het is belangrijk dat het hydraulisch goed in me kaar zit, welke watertemperatuur ook gevraagd wordt, de Dt moet binnen de beperken blijven ook met 100% vermogen, zorg eerst dat de bypass goed ingeregeld wordt, daarna kun je verder, kijk maar naar mijn Dt en stookgedrag van de WP, buurman en jij zullen dan ook blij zijn geen overmatig geluid meer.

Ps. weet niet hoe ik een reactie moet plaatsen, dus nu maar zo.
Succes
Die bypass heeft als functie om de overload aan pompvermogen weg te krijgen als de ketel en warmtepomp samen in werking zijn. In mijn geval zou dat 2500 liter per uur betekenen (ik moet de ketelpomp nog een stand naar beneden zetten, maar ketel moet handmatig aangezet worden dus die draaien nooit tegelijk).
Leuk dat die bypass ook gebruikt kan worden om een Dt van 5 graden te maken bij het opwarmen van een installatie, maar daar is 'ie niet voor bedoeld. Zodra die installatie op temperatuur is werkt 'ie alleen maar tegen.

Ik heb overigens de regeling aangepast naar 7 graden... leuk die 5 graden regeling, maar waar bij 28 graden mijn Dt 2-3 graden is, is dat bij 35 graden een ander verhaal. Door die begrenzing wilde afgelopen weekend de aanvoer niet boven de 33 graden stijgen.

Maargoed, wat het geluid betreft... deze unit is niet heel stil. Hij staat bij mij op de oprit, gericht van de gevel af. Denk dat het zo'n 5-6 meter is naar de gevel van de buurman. Het geluid van de pomp wordt tegen zijn gevel geblazen en komt dan terug. Ik hoor 'm vanaf de zijkanten ook alleen maar omdat het geluid weerkaatst tegen de gevel. Ding staat daar gewoon verkeerd, ik ga 'm deze week met een paar RVS flexpijpen een kwartslag draaien zodat de ventilator over de oprit blaast. Mocht dat ook niet afdoende zijn moet ik hem alsnog verhuizen naar de achtergevel waar 12 meter tuin is tot de garage, is qua leidingen wel te doen maar even een uitdaging om het zonder slopen te doen (schuin gipsplafond).

Wat die Dt betreft: Ik heb hier alleen al in de leidingen al meer dan 25 liter water zitten. Komen de bakbeesten van T22 radiatoren nog bij. Dat water wordt met 1000 liter per uur rondgepompt (pompstand 2, 6 meter opvoerhoogte). Zou nog harder kunnen, maar dat geeft ruis. Langzamer geen optie, dan wordt de radiator van de woonkamer niet meer goed warm.

  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
Vanmorgen op advies van @P1 modubus de pompstand naar 3 gezet om meer flow over de warmtepomp te krijgen. DeltaT is lager over de radiatoren, de vloer in de berging doet goed mee en de warmtepomp is stiller. Pomp gaat minder hard dan wat mijn ketel op stand 3 deed (alhoewel de curves in de handleidingen anders aangeven).

Verder zit er nogal wat lucht in de installatie, dat wordt nu eindelijk mooi rondgepompt en verzamelt in een paar ontluchtingspijpjes op zolder en in een aantal radiatoren op de bovenverdieping.

Komende dagen nog maar wat workarounds uit de software slopen. Met deze flow is de stappenmodulatie niet meer nodig en er zitten nog een aantal andere eigenaardigheden in.
Verder toch eens kijken of ik een ESP aangesloten kan krijgen. Ik zet nu handmatig een hard maximaal setpoint in de thermostaat zodat de warmtepomp 's nachts minder vermogen vraagt, ik wil gewoon een knopje voor een nachtmodus. Verder geeft directe communicatie meer inzichten aangezien ik via OpenTherm alleen afgeronde getallen zie.

  • Ikke83
  • Registratie: Augustus 2024
  • Laatst online: 20-11 21:24
_JGC_ mag ik vragen hoe jij het nu hebt gedaan, ik heb terug gelezen maar kom er toch niet helemaal uit.
wat ik me kan bedenken is het volgende:

- Je hebt de IC (die op een arduino uno zit) geprogrammeerd met een aangepaste code van WackoH en deze dan gewisseld met IC2 in de box
- ik lees dat je solderingen heb gedaan, waar precies? (of zijn dezelfde als WackoH?)
- IC4 heb je verwijderd waardoor je niet hoefde te snijden in de printplaat.
- een DIYLESS gebruik je als vervanger voor Anna, is deze dan aangesloten op de verbindingen van de Smile? zeg maar de meest linker aansluiting.

Bij mij gaat het met de standaard instellingen op zich prima.
Op de een of andere manier kan ik de maximale aanvoertemperatuur niet wijzigen, deze staat standaard (en grijs) op 60.
Op zich is dat geen probleem, want ik gebruik de weersafhankelijke modus. Heel vaak draait ie netjes op 34 graden aanvoer temperatuur, met de heatboosters in mijn convector radiatoren gaat dit heel goed.

Het jammere is dat als de temperatuur bereikt is volgens Anna de gehele warmtepomp uit gaat. Wat natuurlijk logisch is
Het liefst zou ik zien, net als bij jou en WackoH dat de Warmtepomp op iets van 250W gaat draaien zodat er toch iets van een warme luchtstroom (of wat er van over blijft) door het huis gaat. Het gevoel van kilheid komt namelijk snel boven als de Aurea er mee stopt.

alvast bedankt

  • WackoH
  • Registratie: November 2012
  • Laatst online: 26-11 22:38
Ik ben begonnen met een GiHub pagina. Daar ben ik bezig alles samen te vatten, in plaats van dat het als een ontdekkingsreis in posts over een paar maanden verspreid staat. Deze staat nu nog even op private tot die verder is gevuld. Denk dat ik daar dit weekend wel tijd voor heb.

Ik zal dat in het Engels doen zodat er internationaal extra hulp kan komen, want dezelfde buitenunit wordt ook bekend in o.a. UK en Frankrijk gebruikt (wellicht wel met andere interface hardware). Ik vond laatst een aantal Engelse posts van iemand die ook e.e.a. had bereikt.

BIj mij doet de Anna nog steeds de primaire regeling, oftewel de aanvraag voor een bepaalde water aanvoertemperatuur.
Hoe dit wordt bereikt, regelt een Arduino nu i.p.v. de controlbox, Daarin zit een PID regelaar die de gemeten aanvoertemperatuur (bestaande sensor in de warmtepomp op met 0.1oC resolutie) gebruikt om en vermogensvraag te berekenen.
Het totaal is dus en 2-staps regeling, dus primair / secundaire (of aan master/slave control, maar dat is niet meer PC ;) )
Dus ook bij mij gaat de WP uit als de Anna het genoeg vindt. Zonder verstoren (koken geeft veel warmte af) blijft de temperatuur in de woonkamer binnen paar tienden stabiel (vloer + 1 radiator)

  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
Ikke83 schreef op donderdag 20 november 2025 @ 21:24:
_JGC_ mag ik vragen hoe jij het nu hebt gedaan, ik heb terug gelezen maar kom er toch niet helemaal uit.
wat ik me kan bedenken is het volgende:

- Je hebt de IC (die op een arduino uno zit) geprogrammeerd met een aangepaste code van WackoH en deze dan gewisseld met IC2 in de box
- ik lees dat je solderingen heb gedaan, waar precies? (of zijn dezelfde als WackoH?)
- IC4 heb je verwijderd waardoor je niet hoefde te snijden in de printplaat.
- een DIYLESS gebruik je als vervanger voor Anna, is deze dan aangesloten op de verbindingen van de Smile? zeg maar de meest linker aansluiting.

Bij mij gaat het met de standaard instellingen op zich prima.
Op de een of andere manier kan ik de maximale aanvoertemperatuur niet wijzigen, deze staat standaard (en grijs) op 60.
Op zich is dat geen probleem, want ik gebruik de weersafhankelijke modus. Heel vaak draait ie netjes op 34 graden aanvoer temperatuur, met de heatboosters in mijn convector radiatoren gaat dit heel goed.

Het jammere is dat als de temperatuur bereikt is volgens Anna de gehele warmtepomp uit gaat. Wat natuurlijk logisch is
Het liefst zou ik zien, net als bij jou en WackoH dat de Warmtepomp op iets van 250W gaat draaien zodat er toch iets van een warme luchtstroom (of wat er van over blijft) door het huis gaat. Het gevoel van kilheid komt namelijk snel boven als de Aurea er mee stopt.

alvast bedankt
Ik heb de IC die met de warmtepomp communiceert eruit gehaald, die ligt gewoon werkloos bovenop de box.
Ik heb voor nu de solderingen van @WackoH gedaan op de print zodat ik prikpennetjes heb die ik in een Arduino Mega kan stoppen. Het doorsnijden van printbanen heb ik niet gedaan want er zit nu geen chip in de voet.
De DIYLESS komt gewoon op de OT-pinnen waar je normaalgesproken de Smile op aansluit, de Smile en Anna gebruik je dan niet meer.

Overigens kan je met de standaard sturing ook gewoon met de DIYLESS werken. Enig dingetje waar je rekening mee moet houden is dat sommige thermostaten een setpoint blijven doorgeven. De controlbox van de Aurea doet niks met CH_ON, kijkt alleen naar het setpoint. Bij de DIYLESS is dat 10 graden, wat volgens de standaarden voldoet als "uit". De Anna doet daar 0. Bij 20 graden stuurt de DIYLESS een CH_ON, ik begin zelf al eerder met stoken. Een Remeha iSense kan je niet aansluiten, die blijft 24/7 doorstoken.

Het einddoel is om gewoon een Arduino Uno te kopen met verwijderbare chip en die in het voetje te drukken, dan hoef je niks te solderen. Code hoeft daar maar weinig aanpassingen voor.
Ik moet even kijken welke pinnen naar de schakelaar en het ingebouwde LED lampje gaan, waarschijnlijk kan ik op die pinnen dan de communicatie opzetten met een ESP32, hoeft daar alleen een draadje aan met een connector zonder dat er aan de print gesoldeerd hoeft te worden.

Edit: via de pinnen van LED/schakelaar wordt niks als ik de uitgetekende versie van de print goed begrijp. Dan eerder draadjes vastsolderen aan ongebruikte pinnen van de controller. Draadjes bij het voetje indrukken is sowieso no-go.

[ Voor 3% gewijzigd door _JGC_ op 21-11-2025 11:57 ]


  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
Wordt tijd om een printje te solderen, de prikdraadjes is instabiel...

Misschien dat ik de foute data stuur nu het zo koud is, maar de OT controller stuurt prachtig de aanvoer/retour door naar de thermostaat, maar setpoint krijg ik niet meer terug. Er komt geen of te weinig data binnen op RX.

Omdat ik nu toch al aan het prutsen was met een ESP8266 en MQTT heb ik dus maar de thermostaat setpoint gepusht via MQTT. Daarnaast kan ik nu gewoon met een schuifje het maximale schakelpunt van de buitenunit instellen.

Doel: laat de thermostaat lekker op 20.5 of 20 staan 's avonds, schroef het vermogen gewoon terug en we zien wel hoe warm het in de ochtend is, mag dan het schuifje weer naar 5. Ik zit nu nml elke ochtend in de kou en uiteindelijk herrie als ik de thermostaat setpoint omhoog gooi omdat de warmtepomp niet snel genoeg inkomt.

  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
Prikdraadjes is idd instabiel, ook tussen de ESP8266 en de Mega is de communicatie niet zonder storingen. Komt ook omdat die ESP met SoftwareSerial werkt. Dit zal ook de reden zijn waarom de OT controller lijkt te zwijgen, ik krijg soms wel data binnen maar het zijn niet genoeg bytes.

Ik heb nu een Uno R4 Wifi en een paar soldeer printplaten besteld. Printplaatje op maat maken voor de DIP28 socket en de juiste pinnen erin en dan gewoon alles afhandelen vanuit de Uno R4. WP communicatie zal dan met SoftwareSerial moeten. Simpelweg uit de socket aftappen en geen verdere solderingen meer nodig.

  • dingo35
  • Registratie: Februari 2008
  • Laatst online: 00:10
Ik kan als hardware platform de ESP32 aanraden; krachtig genoeg om diverse protocollen te decoderen (RS232, RS485), en superveel libraries beschikbaar om MQTT, web-interface e.d. te maken.

Zie als voorbeeld https://github.com/dingo35/smartevse-3.5/

[ Voor 3% gewijzigd door dingo35 op 26-11-2025 02:47 ]


  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
Nadeel van de ESP32 is 3.3V I/O. Ben al met level shifters of weerstanden bezig geweest, maar de data die uit de warmtepomp krijgt klopt dan niet met wat ik met een 5V controller krijg.

Overigens is de R4 Wifi ook niet de oplossing. Zodra je die aan MQTT knoopt wordt de cycle time 10 seconden.
Gelukkig is de ESP32 op dat ding te flashen, dus kan mijn Mega code in het Uno gedeelte en de ESP8266 code in het ESP32 deel. Is qua flashen wat meer uitdaging.

Overigens ga ik de hele code over de kop gooien. Ik ga zelf OT en ketelsturing doen, dan kan de OT controller er ook uit.

  • dingo35
  • Registratie: Februari 2008
  • Laatst online: 00:10
Is een 74AHCT125 niet een veel simpeler oplossing?

EDIT: voor lezen van signalen zou een 1k weerstand in serie met het signaal al moeten werken, en anders een spanningsdeler 10k/20k. SN74LVC8T245 zou ook moeten werlen...

[ Voor 63% gewijzigd door dingo35 op 26-11-2025 13:41 ]


  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
dingo35 schreef op woensdag 26 november 2025 @ 13:35:
Is een 74AHCT125 niet een veel simpeler oplossing?

EDIT: voor lezen van signalen zou een 1k weerstand in serie met het signaal al moeten werken, en anders een spanningsdeler 10k/20k. SN74LVC8T245 zou ook moeten werlen...
Logic shifter (zo'n goedkoop printje met 4 SMD transistors) had ik geprobeerd, die geeft geen werkend signaal. Die chip heb ik meer vertrouwen in dan een klein printje van Amazon.
Ik heb nu 1K/2K naar ground tussen de ESP en de Arduino Mega, dat werkt.
Ik heb ook even de print bestudeerd, of iig de tekening van @WackoH, er zitten al spanningsdelers in het circuit om er 5V van te maken. Daar dan nog eentje tussen zetten? Lijkt me handiger om te berekenen welke weerstand er dan wel moet komen om de spanningen goed te krijgen.

Maargoed, waar je even mee zit: de buitenunit wil een constant signaal krijgen van de controller, anders slaat 'ie af. Als je 1 controller gebruikt voor Wifi/MQTT, buitenunit communicatie en OpenTherm, kom je met je timings in de problemen zodra je MQTT niet lekker reageert of je wifi signaal slecht is.

Op de R4 Wifi kan je gewoon beide controllers flashen met eigen code, er is over USB dan nog communicatie via de SERIAL_AT poort: https://github.com/vshymanskyy/UNO-R4-WiFi-freedom

Ik ga de Wifi/MQTT code in de ESP32 flashen en dan gewoon data oversturen tussen beide controllers. Zo doe ik het nu ook met de ESP8266 en Mega2650 en dat werkt naar behoren.
OpenTherm ga ik proberen, laatste keer mislukte omdat ik de Ground niet verbonden had. Enige uitdaging daarin is dat de Renesas chip geen AVR architectuur is en de OpenTherm libraries alleen gemaakt zijn voor ESP of AVR. Paar #!ifdef __AVR__ blokken weggesloopt en het compileert, of het dan ook werkt is een 2e.

  • dingo35
  • Registratie: Februari 2008
  • Laatst online: 00:10
_JGC_ schreef op woensdag 26 november 2025 @ 13:59:
[...]


Maargoed, waar je even mee zit: de buitenunit wil een constant signaal krijgen van de controller, anders slaat 'ie af. Als je 1 controller gebruikt voor Wifi/MQTT, buitenunit communicatie en OpenTherm, kom je met je timings in de problemen zodra je MQTT niet lekker reageert of je wifi signaal slecht is.
Ik heb veel ervaring met de SmartEVSE code; daar lezen we meerdere signalen tegelijkertijd uit:
-LCD scherm via SPI
-modbus via UART
-CP lijn via GPIO
....en dat gaat allemaal prima, zelfs onder zware HTTPS belasting, tegelijkertijd met MQTT. Geen problemen als de wifi wegvalt, die reconnect bij hersteld AP signaal gewoon weer netjes terug.

In een prototype communiceren we zelfs met een andere chip via UART2, bovenop al het hierboven genoemde, en dat gaat tot 1Mbps nog foutloos....

Dit zou dus gemakkelijk met een single chip oplossing moeten kunnen. Ik ben zelf meer de software man, als je (een link naar) je schema hebt kan ik het wel eens aan de hardware specialist voorleggen, maar alleen als je echt van plan bent die route op te gaan.

EDIT: De truc zit m erin dat we drie loops hebben, een 10ms loop, een 100ms loop, en een 1000ms loop; de kunst is om de juiste routine in de juiste timingloop aan te roepen, en die de juiste FreeRTOS prio te geven.
EDIT2: De eerlijkheid gebied te melden dat het prototype op een ESP32-S3 draaide, de productie hardware is een "gewone" 4MB ESP32...

[ Voor 12% gewijzigd door dingo35 op 26-11-2025 14:55 ]


  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
@dingo35 Beschrijving van de communicatie zit hier:
WackoH in "Aurea 5 hybrid: interfaces met de buitenunit en thermostaat"

Tekening van de hardware zit in deze post:
WackoH in "Aurea 5 hybrid: interfaces met de buitenunit en thermostaat"

Code "werkt", maar is voor verbetering vatbaar. Ik vind het vooral onleesbaar. Heb een informatica opleiding genoten maar ben geen MCU-programmeur. Die code ga ik zeker herschrijven :)

Schijnt dat de timing niet eens heel idioot hoeft te kloppen, maar die 10 seconden zoals ik gisteren zag bij het opzetten van MQTT met een R4 Wifi slaat helemaal nergens op. Dat doet zelfs een ESP8266 beter. Vandaar dat ik de ESP zelf wil programmeren. Vind het zonde van de hardware dat ze het zo hebben opgelost.

  • P1 modubus
  • Registratie: Maart 2023
  • Laatst online: 11:47
Dingo schreef,
Ik heb veel ervaring met de SmartEVSE code; daar lezen we meerdere signalen tegelijkertijd uit:
-LCD scherm via SPI
-modbus via UART
-CP lijn via GPIO
....en dat gaat allemaal prima, zelfs onder zware HTTPS belasting, tegelijkertijd met MQTT. Geen problemen als de wifi wegvalt, die reconnect bij hersteld AP signaal gewoon weer netjes terug.

Weten jullie of de Arduino of de Raspberry pi kan communiceren via Modbus RTU met de seriële verbinding,
ik wil namelijk de weersverwachting doorgeven aan de HVAC regeling.?

  • dingo35
  • Registratie: Februari 2008
  • Laatst online: 00:10
De ESP32 kan zeker via de UART met modbus RTU communiceren, daar zijn ook verschillende modbus libraries voor; voor code voorbeeld zie de github repo enkele posts up.

  • WackoH
  • Registratie: November 2012
  • Laatst online: 26-11 22:38
_JGC_ schreef op woensdag 26 november 2025 @ 15:24:
Code "werkt", maar is voor verbetering vatbaar. Ik vind het vooral onleesbaar. Heb een informatica opleiding genoten maar ben geen MCU-programmeur. Die code ga ik zeker herschrijven :)
Ik lees mee, heh…. Iets vriendelijker en minder arrogant/neerbuigend mag wel... 😉

Bij mij WERKT het perfect en robuust: Temperatuur binnen paar tienden stabiel, software crasht of hangt nooit. De Plugwise functionaliteit met Anna thermostaat, weersafhankelijke regeling (stooklijn), gebruik van app en HA integratie zijn volledig behouden en verbindingen zijn zeer stabiel. Dit is allemaal belangrijk voor de PAF (Partner Acceptance Factor).
Opgenomen vermogen zie ik via tussenstekker met Zigbee op HA.

Zou wel eens de best werkende Aurea in Nederland kunnen zijn😊
Ik kan zelfs koelen als ik zou willen.

De code is zoveel mogelijk geoptimaliseerd voor snelheid (met AI) omdat het schrijven naar het schermpje dat ik heb gebruikt veel tijd vraagt. En ja, dat maakt het lastig leesbaar. Maar ik heb voor jullie zo veel mogelijk toelichting erbij gezet.

De problemen die je noemt zijn bv. het gevolg van een andere manier van hardware implementatie en de manier waarop je het setpoint voor de aanvoertemperatuur geeft.

Het is een projectje geweest dat in de loop van de tijd is gegroeid. Van de aansturing begrijpen, via berichten minimaal modificeren tot nu volledige besturing nu. Dus ja, dan is het niet perfect en de code is ongetwijfeld voor verbetering vatbaar.

Met de kennis van nu zou ik het ook anders opzetten. Hiervoor heb ik al een touchscreen met ESP32 liggen. Maar waarom wijzigen wat ik nu heb? Het is goed genoeg en de Aurea gaat te weinig capaciteit hebben als ik huis uitbreid.

  • _JGC_
  • Registratie: Juli 2000
  • Laatst online: 11:22
@WackoH Je rotary encoder voorbeeld is gewoon duidelijk. Probleem met de latere regeling is dat er heel veel dingen zijn toegevoegd en waar je later in hebt gesnoeid om het deelbaar op het forum te maken. Vervolgens heb ik daar nog een en ander in verbouwd waar het ook niet duidelijker van wordt. Niet om arrogant of neerbuigend te doen, ik ben juist heel blij met wat jij voor dit topic betekent. Zonder jouw werk was dit niet mogelijk geweest.

Zoals het nu lijkt ga ik je rotary encoder voorbeeld gebruiken, daar OpenTherm communicatie aan toevoegen en dan wat statistieken uitpoepen via die ESP controller naar MQTT. Via MQTT bepaal ik ook de maximale speed setpoint zodat ik een nachtmodus heb. Die OT controller gaat dus ook uit de box als het aan mij ligt.

Vandaag de hele dag op stand 2 en 3 gedraaid, vanmorgen 3 defrosts. Tussendoor is de warmtepomp even een uur uit geweest en vannacht 3x een halfuur uit. In de nacht gaat het maximale vermogen naar stand 2 (alhoewel de buitenunit soms alsnog eigenwijs 650W gaat draaien). Het is hier nu dag en nacht 20.3 graden met aanvoertemperatuur tussen 28 en 37 graden.

Enig dingetje is dat mijn sluipverbruik op slimmemeterportaal nu van 80W naar 546W is gegaan.

[ Voor 6% gewijzigd door _JGC_ op 26-11-2025 23:47 ]

Pagina: 1 2 Laatste