La séptima vida

...o el gato así lo espera/teme

Device::Modbus and Taisuo's CH3000 temperature controllers

Today I worked with some Taisuo CH3000 temperature controllers. One of the two devices I am working with stopped communicating, but it was quite difficult to configure the Modbus address on a replacement controller. This is what I learned.

The Modbus address of these devices is mostly read-only. It can be changed by turning on the controller with the "S" key pressed for three seconds, which enters the device into a special mode with factory-defined communication parameters. In this mode, it is possible to change communication parameters to suit your application.

The green power indicator blinks when the controller is in this mode. The device responds on Modbus address 247, 9600 baud and no parity (or address 1). Once changes are made, the controller must be restarted for the new address to take effect. The baud rate returns to whatever you had before entering this programming mode.

The problem is that the whole procedure is just vaguely documented. So, I did not have a productive evening. This took from 4:30pm to 8:30pm.

Part of the problem was solved with a Modbus client written in Perl, which also uncovered a bug in Device::Modbus::Client. It was never reading the port. It is now fixed.

I got to write three simple scripts to work through the controller set-up. The first one interrogates the controller; the second searches through several addresses to find a controller, and the third actually changes the Modbus address.

This is the program that tests some addresses looking for a controller:

#! /usr/bin/env perl

use Device::Modbus::RTU::Client;
use Data::Dumper;
use strict;
use warnings;
use v5.10;

my $client = Device::Modbus::RTU::Client->new(
port => '/dev/ttyUSB0',
baudrate => 9600,
parity => 'none',

foreach my $addr (1, 2, 3, 4, 5, 247) {

say "Modbus unit: $addr";

my $req = $client->read_holding_registers(
unit => $addr,
address => 46,
quantity => 3,


my $resp;
eval {
$resp = $client->receive_response;
next if $@;

say "<-" . Dumper $resp;