Skip to content

Commit 5e5fe6c

Browse files
committed
interactive OpenTherm shield testing program
1 parent c8370aa commit 5e5fe6c

File tree

1 file changed

+237
-0
lines changed

1 file changed

+237
-0
lines changed
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
/**
2+
* \file shield_test.ino
3+
* \brief This Arduino program is a diagnostic tool designed to test and validate the electrical and communication integrity
4+
* between a boiler and thermostat circuits on the OpenTherm shield.
5+
* It guides the user through a step-by-step verification process via serial prompts, checking voltages, currents, and LED statuses.
6+
* The setup() function initializes hardware pins and performs sequential tests with user measurements and confirmation,
7+
* while the loop() continuously validates bidirectional signal communication between boiler and thermostat if all initial tests pass.
8+
* The program provides real-time feedback via serial output, indicating "TEST PASSED" or "TEST FAIL" based on user input and hardware responses.
9+
*
10+
* \copyright SPDX-FileCopyrightText: Copyright 2025 Michal Protasowicki
11+
*
12+
* \license SPDX-License-Identifier: MIT
13+
*
14+
*/
15+
16+
#if !defined(ARDUINO_ARCH_AVR)
17+
#error "Use only with Arduino AVR family!!!"
18+
#endif
19+
20+
#include <Arduino.h>
21+
22+
// Arduino UNO
23+
const int MASTER_IN {2};
24+
const int SLAVE_IN {3};
25+
const int MASTER_OUT {4};
26+
const int SLAVE_OUT {5};
27+
28+
const int DELAY_DEV_MS {40};
29+
const int DELAY_LOOP_MS {2000};
30+
31+
const char CONFIRM_M_STR[] PROGMEM {"If the measurement is correct, send 'y' to proceed to the next step."};
32+
const char CONFIRM_P_STR[] PROGMEM {"If so, press 'y' to proceed to the next step."};
33+
const char MASTER_ACT_STR[] PROGMEM {"The 'MASTER-OUT' line has been activated."};
34+
const char RXT_NLIT_STR[] PROGMEM {"The RxT LED should not be lit during the measurement."};
35+
const char MEAS_B1_B2_STR[] PROGMEM {"Measure the voltage between test points B1 and B2."};
36+
const char FAILED_STR[] PROGMEM {"Failed"};
37+
const char OK_STR[] PROGMEM {"OK"};
38+
const char LINE_STR[] PROGMEM {"----------------------------------------------------------------------------------"};
39+
const char STARS_STR[] PROGMEM {"*****************"};
40+
41+
bool next {false};
42+
43+
bool waitForYes(void)
44+
{
45+
bool result {true};
46+
bool exit {false};
47+
char chr {0};
48+
49+
while (!exit)
50+
{
51+
while (!SERIAL_PORT_MONITOR.available()) {};
52+
while (SERIAL_PORT_MONITOR.available() > 0)
53+
{
54+
chr = SERIAL_PORT_MONITOR.read();
55+
56+
switch (chr)
57+
{
58+
case 'n':
59+
case 'N':
60+
exit = true;
61+
result = false;
62+
break;
63+
case 'y':
64+
case 'Y':
65+
exit = true;
66+
break;
67+
default:
68+
break;
69+
}
70+
}
71+
}
72+
73+
return result;
74+
}
75+
76+
void setup()
77+
{
78+
SERIAL_PORT_MONITOR.begin(115200);
79+
while (!SERIAL_PORT_MONITOR) {}
80+
81+
pinMode(MASTER_IN, INPUT);
82+
pinMode(SLAVE_IN, INPUT);
83+
pinMode(MASTER_OUT, OUTPUT); // low output = high current, high output = low current
84+
pinMode(SLAVE_OUT, OUTPUT); // low output = high voltage, high output = low voltage
85+
digitalWrite(MASTER_IN, HIGH);
86+
digitalWrite(MASTER_OUT, HIGH);
87+
digitalWrite(SLAVE_IN, HIGH);
88+
digitalWrite(SLAVE_OUT, LOW);
89+
90+
SERIAL_PORT_MONITOR.println(F("Disconnect the 'THERM' and 'BOILER' terminals if they are connected to each other."));
91+
SERIAL_PORT_MONITOR.println(F("The 'PWR' and 'RxT' LEDs should light up, and the 'RxB' LED should be off."));
92+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)CONFIRM_P_STR);
93+
next = waitForYes();
94+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)LINE_STR);
95+
96+
if (next)
97+
{
98+
SERIAL_PORT_MONITOR.println(F("Measure the voltage between the +24V test point and GND."));
99+
SERIAL_PORT_MONITOR.println(F("It should be between 23.5V and 24.5V."));
100+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)CONFIRM_M_STR);
101+
next = waitForYes();
102+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)LINE_STR);
103+
}
104+
105+
if (next)
106+
{
107+
SERIAL_PORT_MONITOR.println(F("Measure the voltage between the T+ test point and GND."));
108+
SERIAL_PORT_MONITOR.println(F("It should be approximately 24V."));
109+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)CONFIRM_M_STR);
110+
next = waitForYes();
111+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)LINE_STR);
112+
}
113+
114+
if (next)
115+
{
116+
SERIAL_PORT_MONITOR.println(F("Measure the current flowing between the T+ test point and GND."));
117+
SERIAL_PORT_MONITOR.println(F("It should be between 5mA and 9mA."));
118+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)RXT_NLIT_STR);
119+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)CONFIRM_M_STR);
120+
next = waitForYes();
121+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)LINE_STR);
122+
}
123+
124+
if (next)
125+
{
126+
digitalWrite(MASTER_OUT, LOW);
127+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)MASTER_ACT_STR);
128+
SERIAL_PORT_MONITOR.println(F("Measure the current flowing between the T+ test point and GND again."));
129+
SERIAL_PORT_MONITOR.println(F("It should be between 17mA and 23mA."));
130+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)RXT_NLIT_STR);
131+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)CONFIRM_M_STR);
132+
next = waitForYes();
133+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)LINE_STR);
134+
digitalWrite(MASTER_OUT, HIGH);
135+
}
136+
137+
if (next)
138+
{
139+
SERIAL_PORT_MONITOR.println(F("Connect the BOILER and THERM terminals with two wires [polarity is irrelevant]."));
140+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)MEAS_B1_B2_STR);
141+
SERIAL_PORT_MONITOR.println(F("It should be between 15V and 18V."));
142+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)CONFIRM_M_STR);
143+
next = waitForYes();
144+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)LINE_STR);
145+
}
146+
147+
if (next)
148+
{
149+
digitalWrite(MASTER_OUT, LOW);
150+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)MASTER_ACT_STR);
151+
SERIAL_PORT_MONITOR.println(F("The 'RxB' LED should light up."));
152+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)CONFIRM_P_STR);
153+
next = waitForYes();
154+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)LINE_STR);
155+
digitalWrite(MASTER_OUT, HIGH);
156+
}
157+
158+
if (next)
159+
{
160+
digitalWrite(SLAVE_OUT, HIGH);
161+
SERIAL_PORT_MONITOR.println(F("The 'SLAVE-OUT' line has been activated."));
162+
SERIAL_PORT_MONITOR.println(F("The RxT LED should stop lighting up."));
163+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)MEAS_B1_B2_STR);
164+
SERIAL_PORT_MONITOR.println(F("It should be between 5V and 7V."));
165+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)CONFIRM_M_STR);
166+
next = waitForYes();
167+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)LINE_STR);
168+
digitalWrite(SLAVE_OUT, LOW);
169+
}
170+
171+
172+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)STARS_STR);
173+
if (next)
174+
{
175+
SERIAL_PORT_MONITOR.println(F("* TEST PASSED *"));
176+
} else
177+
{
178+
SERIAL_PORT_MONITOR.println(F("* TEST FAIL !!! *"));
179+
}
180+
SERIAL_PORT_MONITOR.println((const __FlashStringHelper *)STARS_STR);
181+
}
182+
183+
void loop()
184+
{
185+
if (next)
186+
{
187+
Serial.print(F("Boiler inbound, thermostat outbound ... "));
188+
digitalWrite(MASTER_OUT, HIGH);
189+
digitalWrite(SLAVE_OUT, HIGH);
190+
delay(DELAY_DEV_MS);
191+
192+
if ((LOW == digitalRead(MASTER_IN)) && (LOW == digitalRead(SLAVE_IN)))
193+
{
194+
digitalWrite(MASTER_OUT, LOW); // thermostat out low -> boiler in high
195+
delay(DELAY_DEV_MS);
196+
197+
if ((LOW == digitalRead(MASTER_IN)) && (HIGH == digitalRead(SLAVE_IN)))
198+
{
199+
Serial.println((const __FlashStringHelper *)OK_STR);
200+
} else
201+
{
202+
Serial.println((const __FlashStringHelper *)FAILED_STR);
203+
Serial.println(F("Boiler is not registering signal or thermostat is not sending properly"));
204+
}
205+
} else
206+
{
207+
Serial.println((const __FlashStringHelper *)FAILED_STR);
208+
Serial.println(F("Boiler is high even if no signal is being sent"));
209+
}
210+
211+
Serial.print(F("Boiler outbound, thermostat inbound ... "));
212+
digitalWrite(MASTER_OUT, HIGH);
213+
digitalWrite(SLAVE_OUT, HIGH);
214+
delay(DELAY_DEV_MS);
215+
216+
if ((LOW == digitalRead(MASTER_IN)) && (LOW == digitalRead(SLAVE_IN)))
217+
{
218+
digitalWrite(SLAVE_OUT, LOW); // boiler out low -> thermostat in high
219+
delay(DELAY_DEV_MS);
220+
221+
if ((HIGH == digitalRead(MASTER_IN)) && (LOW == digitalRead(SLAVE_IN)))
222+
{
223+
Serial.println((const __FlashStringHelper *)OK_STR);
224+
} else
225+
{
226+
Serial.println((const __FlashStringHelper *)FAILED_STR);
227+
Serial.println(F("Thermostat is not registering signal or boiler is not sending properly"));
228+
}
229+
} else
230+
{
231+
Serial.println((const __FlashStringHelper *)FAILED_STR);
232+
Serial.println(F("Thermostat is high even if no signal is being sent"));
233+
}
234+
235+
delay(DELAY_LOOP_MS);
236+
}
237+
}

0 commit comments

Comments
 (0)