Read out from heatpump

Hi Guys,

I'm new to the world of Arduino and programming.
I need some guidance for this project.

I have a heatpump manufactured by IVT, which uses a REGO637 controller. The REGO is equipped with a service port, a TTL 5V comunication and Communication always using 19200 bps, 8 bit, no parity, 1 stop bit (19200/8N1). This is 5V CMOS 4000 (TTL) signals.

I want to read out temperatures and alarms from this heatpump using an arduino, then forward the measurment to a KNX home automation system. I have already managed to connect an Arduino PRO mini, to a KNX Bus Tranciever Unit (BTU) to transmit to the KNX bus, there was already an API for that, so I haven't actually done anything but using the API.

From what I can see, the PRO mini only have 1 serial connection? And in my case I'll need 2, one to connect to the KNX BTU, bt also one to connect to the heatpump service port. is this possible with the MEGA? Or do I need 2 Arduinos who communicate with eachother in some how?

Do anyone know about a library that I could use for my connection to the Heatpump? I haven't found anyone trying this yet, only other platforms, but not arduino.
My programming skills are really bad, is there anyone who might want to jump in and help coding?

Here is a good project that describes the REGO controller, and how to communicate with it.
http://rago600.sourceforge.net/

Best regards
Manne C

You can use SoftwareSerial or one of its alternatives to effectively add another port, however beware that there are some problems with it. It should work OK at 19200 Baud. The Mega has four hardware serial ports.

Thanks!
How about uno?

Wich controller would you recomend for this Project?

I would use either a Mega or a Micro because they have a spare HardwareSerial port for communicating with your Heat Pump. The Uno and Mini and Nano use the Atmega 328 chip which has only one HardwareSerial port and that is normally used for uploading programs and communicating with the PC.

The examples in Serial Input Basics may be useful - simple reliable ways to receive data. There is also a parse example.

...R

Thanks for your input and the link, I will read it tonight :slight_smile:
Will the Micro be able to handle all the code in term of memory and such?

sx3000:
Will the Micro be able to handle all the code in term of memory and such?

Probably. But without seeing your code I can't be sure.

...R

Thanks,
I don't have any code yet so I'll go the safe road and go with the MEGA, for the final product I'll try to fit it in a micro. :slight_smile:

Allright, so I have managed to find a Lib that communicate the heatpump, on Github.
Unfortunatly, there isn't any example code. Just the CPP and H file, and as a noob, I'm not sure how to use the functions of the Lib.

The lib can be found here:

I would appriciate if someone could me get started by filling in, on my test-draft. Don't mind the Serial0, thats for the KNX TP-UART interface.

#include <Rego600.h>
#include <KnxTelegram.h>
#include <KnxTpUart.h>

KnxTpUart knx(&Serial, "1.1.59"); // for Pro Mini

void setup() {
  // Serial = KNX TP-UART
  // Serial1 = REGO-600 Controller


  Serial.begin(19200);

  UCSR0C = UCSR0C | B00100000; // for Pro Mini
  Serial.print("UCSR1A: ");
  Serial.println(UCSR0A, BIN);

  Serial.print("UCSR0B: ");
  Serial.println(UCSR0B, BIN);

  Serial.print("UCSR0C: ");
  Serial.println(UCSR0C, BIN);
  knx.uartReset();
  
  Serial1.begin(19200);
}

void loop() {
 // Serial.print("Hello world");      //Skickar på serieport 0
 // Serial1.print("Hello world");      //Skickar på serieport 1
 // Serial2.print("Hello world");      //Skickar på serieport 2
 // Serial3.print ("Hello world");      //Skickar på serieport 3

}
#ifndef Rego600_h
#define Rego600_h

#include <inttypes.h>

#define REGO_600 0x81

// 1 - address 5char 16bit number Read from front panel (keyboard+leds) {reg09FF+xx}
#define PANEL_R 0x00
// 2 - address + data 1char confirm Write to front panel (keyboard+leds) {reg 09FF+xx}
#define PANEL_W 0x01
// 1 - address 5char 16bit number Read from system register (heat curve, temperatures, devices) {reg 1345+xx}
#define REGISTER_R 0x02
// 2 - address + data 1char confirm Write into system register (heat curve, temperatures, devices) {reg 1345+xx}
#define REGISTER_W 0x03
// 1 - address 5char 16bit number Read from timer registers {reg 1B45+xx}
#define TIMER_R 0x04
// 2 - address + data 1char confirm Write into timer registers {reg 1B45+xx}
#define TIMER_W 0x05
// 1 - address 5char 16bit number Read from register 1B61 {reg 1B61+xx}
#define REGISTER_HI_R 0x06
// 2 - address + data 1char confirm Write into register 1B61 {1B61+xx}
#define REGISTER_HI_W 0x07
// 1 - display line 42char text line Read from display {0AC7+15h*xx}
#define DISPLAY_R 0x20
// 0 42char text line Read last error line [4100/00]
#define ERROR_LAST 0x40
// 0 42char text line Read previous error line (prev from last reading) [4100/01]
#define ERROR_PREVIUS 0x42
// 0 5char 16bit number Read rego version {constant 0258 600 ?Rego 600?}

#define VERSION 0x7F

// Rego636-... Register
// Sensor values
#define RADIATOR_RETURN_GT1 0x020B // Radiator return[GT1]
#define OUTDOOR_TEMP_GT2 0x020C // Outdoor [GT2]
#define HOT_WATER_GT3 0x020D // Hot water [GT3]
#define FORWARD_GT4 0x020E // Forward [GT4]
#define ROOM_GT5 0x020F // Room [GT5]
#define COMPRESSOR_GT6 0x0210 // Compressor [GT6]
#define HEAT_FLUID_OUT_GT8 0x0211 // Heat fluid out [GT8]
#define HEAT_FLUID_IN_GT9 0x0212 // Heat fluid in [GT9]
#define TRANSFER_FLUID_IN_GT10 0x0213 // Cold fluid in [GT10]
#define TRANSFER_FLUID_OUT_GT11 0x0214 // Cold fluid out [GT11]
#define HOT_WATER_EXTERNAL_GT3X 0x0215 // External hot water [GT3x]

// Device values
#define GROUND_LOOP_PUMP_P3 0x01FF // Ground loop pump [P3]
#define COMPRESSOR 0x0200 // Compressor
#define ADDITIONAL_HEAT_STEP_1 0x0201 // Additional heat 3kW
#define ADDITIONAL_HEAT_STEP_2 0x0202 // Additional heat 6kW
#define RADIATOR_PUMP_P1 0x0205 // Radiator pump [P1]
#define HEAT_CARRIER_PUMP_P2 0x0206 // Heat carrier pump [P2]
#define THREE_WAY_VALVE 0x0207 // Tree-way valve [VXV]
#define ALARM 0x0208 // Alarm

// Control data
#define ADDED_HEAT_POWER 0x006C // Add heat power in %
#define GT4_TARGET_VALUE 0x006D // GT4 Target value
#define GT1_TARGET_VALUE 0x006E // GT1 Target value
#define GT1_ON_VALUE 0x006F // GT1 On value
#define GT1_OFF_VALUE 0x0070 // GT1 Off value
#define GT3_TARGET_VALUE 0x002B // GT3 Target value
#define GT3_ON_VALUE 0x0073 // GT3 On value
#define GT3_OFF_VALUE 0x0074 // GT3 Off value

// Settings
#define HEAT_CURVE 0x0000 // Heat curve
#define HEAT_CURVE_FINE 0x0001 // Heat curve fine adj.
#define HEAT_CURVE_COUPLING_DIFF 0x0002 // Heat curve coupling diff.
#define ADJ_CURVE_AT_N35_DGR_OUT 0x0008 // Adj. curve at -35C out
#define ADJ_CURVE_AT_N30_DGR_OUT 0x000A // Adj. curve at -30C out
#define ADJ_CURVE_AT_N25_DGR_OUT 0x000C // Adj. curve at -25C out
#define ADJ_CURVE_AT_N20_DGR_OUT 0x000E // Adj. curve at -20C out
#define ADJ_CURVE_AT_N15_DGR_OUT 0x0010 // Adj. curve at -15C out
#define ADJ_CURVE_AT_N10_DGR_OUT 0x0012 // Adj. curve at -10C out
#define ADJ_CURVE_AT_N5_DGR_OUT 0x0014 // Adj. curve at -5C out
#define ADJ_CURVE_AT_0_DGR_OUT 0x0016 // Adj. curve at 0C out
#define ADJ_CURVE_AT_5_DGR_OUT 0x0018 // Adj. curve at 5C out
#define ADJ_CURVE_AT_10_DGR_OUT 0x001A // Adj. curve at 10C out
#define ADJ_CURVE_AT_15_DGR_OUT 0x001C // Adj. curve at 15C out
#define ADJ_CURVE_AT_20_DGR_OUT 0x001E // Adj. curve at 20C out
#define INDOOR_TEMP_SETTING 0x0021 // Indoor temp setting
#define CURVE_INFL_IN_TEMP 0x0022 // Curve infl. by in-temp.


class Rego600 {
private:
	uint8_t request[9];
	char shortResult[5];
	char longResult[42];
	char textResult[20];

	uint8_t *buildRequest(uint8_t address, uint8_t command, uint16_t reg, int value);

	int result2int(char *result);

	char *result2text(char *result);

	void sendRead(uint8_t *request, char *result);

	void read(char *result);

	void send(uint8_t *request);

public:
	int getRegisterValue(uint16_t reg);

	double getRegisterValueTemperature(uint16_t reg);

	int getValue(uint8_t address, uint8_t command, uint16_t reg);

	char *getDisplayLine(uint8_t line);

	char *getText(uint8_t address, uint8_t command, uint16_t reg);

	char *getLongData(uint8_t address, uint8_t command, uint16_t reg);

};

#endif
#include "Rego600.h"

#include <inttypes.h>
#include <stdint.h>
#include "Arduino.h"

int Rego600::getRegisterValue(uint16_t reg) {
	return getValue(REGO_600, REGISTER_R, reg);
}

double Rego600::getRegisterValueTemperature(uint16_t reg) {
	if (reg >= RADIATOR_RETURN_GT1
			&& reg <= HOT_WATER_EXTERNAL_GT3X) {
		reg -= 2;
	}
	double d = getValue(REGO_600, REGISTER_R, reg) * .1;
	return d;
}

int Rego600::getValue(uint8_t address, uint8_t command, uint16_t reg) {
	uint8_t *request = buildRequest(address, command, reg, 00);
	sendRead(request, shortResult);
	return result2int(shortResult);
}

char *Rego600::getDisplayLine(uint8_t line) {
	return getText(REGO_600, DISPLAY_R, line);
}

char *Rego600::getText(uint8_t address, uint8_t command, uint16_t reg) {
	char *result = getLongData(address, command, reg);
	return result2text(result);
}

char *Rego600::getLongData(uint8_t address, uint8_t command, uint16_t reg) {
	uint8_t *request = buildRequest(address, command, reg, 00);
	sendRead(request, longResult);
	return longResult;
}

uint8_t *Rego600::buildRequest(uint8_t address, uint8_t command, uint16_t reg, int value) {
	request[0] = address;
	request[1] = command;

	uint8_t sum = 0;

	for (int poc = 0; poc <= 2; poc++) {
		uint8_t b = (reg & 0x7F);
		request[4 - poc] = b;
		sum = (sum ^ b);
		reg = reg >> 7;
	}
	for (int poc = 0; poc <= 2; poc++) {
		uint8_t b = (value & 0x7F);
		request[7 - poc] = b;
		sum = (sum ^ b);
		value = value >> 7;
	}
	request[8] = sum;
	return request;
}

int Rego600::result2int(char *result) {
	int num = result[1] * 16384 + result[2] * 128 + result[3];
	if (result[1] >= 2) {
		num -= (65536);
	}
	return num;
}

char *Rego600::result2text(char *result) {
	for (int i = 1; i <= 20; i++) {
		char c = (result[(i * 2)] << 4) + result[1 + (i * 2)];
		textResult[i]=c;
	}
	return textResult;
}

void Rego600::sendRead(uint8_t *request, char *result) {
	send(request);
	read(result);
}

void Rego600::read(char *result) {
//	while (inputStream::available() < length) {
//			delay(100);
//	}
//	inputStream::read(result);
//	if (result[0] != 01) {
//		return 0;
//	}
//	int checksum = 0;
//	for (int j = 1; j < sizeof(result) / sizeof(result[0]) - 1; j++) {
//		checksum ^= result[j];
//	}
//	Serial.read(result);
}

void Rego600::send(uint8_t *data) {
//	outputStream::write(data);
}

Did you manage it?

No I never figured out how the code works. :frowning:
But I'm still interested into getting this to work! :slight_smile:

SX3000
++Karma for being willing to get stuck in and try stuff, unlike too many new people on here that just want everything done for them.

If I were doing this I'd probably connect the heat pump serial port to an Arduino and use a short program to take whatever the heat pump outputs and dump it unchanged to the serial monitor. From that I'd try to work out what the data means.

I'm willing to learn, but sometimes I can't do it on my own. I'm not expecting other to do the work for me, but I would need someone to walk my side and show guidance some times.
I'm going to try what you suggested @PerryBebbington, however I'll first need to understand the code and what it's doing.

Why not write to the guy who wrote the library and ask for example code?

The library just accesses some registers on the heat pump. If you don't know what to expect from them, the task is almost hopeless.

@jremington

I tried asking by opening an issue on GitHub 2½ years ago. No reply from anyone.
I know what the registers are and what values they should output (the same as the actual display on the heat pump)

I guess I won't need to poll the heat pump, the heat pump will output values upon change.

The *.h file is the library right? the *.cpp is that the sketch?

Both .h and .cpp comprise the library. The functions listed under "public:" in the .h file are ones you can call from your Arduino program.

public:
	int getRegisterValue(uint16_t reg);

	double getRegisterValueTemperature(uint16_t reg);

	int getValue(uint8_t address, uint8_t command, uint16_t reg);

	char *getDisplayLine(uint8_t line);

	char *getText(uint8_t address, uint8_t command, uint16_t reg);

	char *getLongData(uint8_t address, uint8_t command, uint16_t reg);

It appears that the library is set up so that you could #include the .cpp file in your Arduino program, and that will bring in the .h file.

I start to understand the topology, thanks! :slight_smile:
From what I can tell, the *.cpp already calls the "public" from the *.h file. How do I call a register from my sketch?

How would a call look like, to write out this from the *.h on serial?
#define RADIATOR_RETURN_GT1 0x020B // Radiator return[GT1]

Do I include the *.cpp as simple as with with *.h?

#include "test.cpp"

If you simply put both the .cpp and the .h files in the same directory as your Arduino program, they should automatically be included. But this feature does not always work correctly.

However, if you don't know how to call a function in a library, you have skipped most, if not all of the usual introductory steps in learning Arduino. Expect a great deal of frustration and waste of time with that approach.

But here is one thing that your Arduino program might do:

Serial.println(getRegisterValue(reg)); //substitute "reg" with appropriate register address

Thanks, you are correct about me not knowing. :slight_smile: I played around a couple of years ago but I have forgotten most of it. I will go back for the basics although I know how to output/print on serial.

My last question wasn't that clear I think. What I'm trying to figure out is where the serial parameter are set for the serial communication, such as baudrate, handshake and so. Because we will need to read out the info from the HP before we can output it somewhere. From what I understand the CPP and H file doesn't contrain thoose paratameters, neither the ones to send a read-request.
Thoose would be in the INO file, Unfortunatly there isn't any *.ino files on that GitHub that would help me out.

Use Serial.begin() or other appropriate .begin() method to set Baud rate, etc. on Arduino.

The serial reads and writes are commented out in the library code, so it is currently nonfunctional.

void Rego600::read(char *result) {
//	while (inputStream::available() < length) {
//			delay(100);
//	}
//	inputStream::read(result);
//	if (result[0] != 01) {
//		return 0;
//	}
//	int checksum = 0;
//	for (int j = 1; j < sizeof(result) / sizeof(result[0]) - 1; j++) {
//		checksum ^= result[j];
//	}
//	Serial.read(result);
}

void Rego600::send(uint8_t *data) {
//	outputStream::write(data);
}

Okey, if we assume the code is flawless and we uncomment the serial reads.
Would this sketch be appropriate to read out one register and output it on different serial?

#include "Rego600.cpp"

void setup() {
  Serial.begin(19200); //This is the serial (8N1) from the Heat Pump
  Serial3.begin(19200); //This is the serial (8N1) where we want the reading from the Heat Pump to output

}

void loop() {

  Serial3.println(getRegisterValue(RADIATOR_RETURN_GT1)); //Gets value from Serial and outputs on Serial3
  delay(5000); //Lets wait 5 seconds, then we get it again
}