Решение для majordomo
На авторство не претендую, всего лишь собрал разрозненные данные по сети и отмел откровенно неработающие.
Сразу скажу, что ни один готовый модуль счетчиков из маркета с моим 206 нормально не заработал, равно не заработали и многочисленные python и php-скрипты, которые я находил на форуме и в интернете.
Для начала, я уверен, что вы уже ознакомились с базовой статьей уважаемого directman66
https://connect.smartliving.ru/profile/1502/blog/k...
и уже имеете конвертер rs-485 на USB и установили правильные драйвера и ser2net на ваше устройство, об этом всем можно прочитать в статье выше.
В качестве устройства можно использовать роутер, малину/апельсину с установленным majordomo или без, я использую orange pi zero, на следующем этапе хочу заменить ее на ESP или Wemos.
Также, понадобится серийный номер счетчика, он написан на его морде, а программно получить у вас его не удастся, даже через стандартное приложение под винду.
Следующим шагом нам понадобится правильная строка инициализации порта для ser2net, на стандартных - не взлетит.
Вот она
3020:raw:0:/dev/ttyUSB0:9600 NONE 1STOPBIT 8DATABITS -XONXOFF -LOCAL -RTSCTS
Мне подсказал ее не менее уважаемый stellhawk с форума mjdm.
Далее, адаптируем php-скрипт отсюда, это единственное, что у меня сработало с 206
https://github.com/stell-hawk/mercury206/blob/mast...
DEFINE('MDEBUG',FALSE);
$error = "";
$error1 = "";
class mercury206_lib
{
public $socket;
public $host;
public $port;
public $addr;
public $connected=false;
public $timeout=1;
function __construct($host,$port,$addr)
{
$this->host=$host;
$this->port=$port;
$this->addr=str_pad(dechex($addr),8,"0",STR_PAD_LEFT);
$this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (!$this->socket) $error='Unable to create socket';
socket_set_option($this->socket,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>$this->timeout, "usec"=>0));
//echo 'created socket'.$this->socket.'\n';
$this->connected=@socket_connect($this->socket,$this->host,$this->port);
if (!$this->connected) $error='Unable to connect to '.$this->host.":".$this->port;
}
function send($in)
{
$in=hex2bin($in);
socket_send($this->socket,$in,strlen($in),MSG_EOF);
$ret=socket_read($this->socket,1024);
//шлем дополнительную команду чтобы счетчик не разорвал соединение (актуально только для чтения кВт*ч - там слишком большой ответ) в остальных случаях можно и не слать
socket_send($this->socket,hex2bin("f2"),strlen($in),MSG_EOF);
$ret.=socket_read($this->socket,1024);
return bin2hex($ret);
}
function send_ret($code)
{
$msg=$this->addr.$code;
$msg=$msg.$this->crc16_modbus($msg);
if(MDEBUG)echo "\nsend: ".$this->nice_hex($msg)."\n";
$ret=$this->send($msg);
if(MDEBUG)echo "\nret(".strlen($ret).") :".$this->nice_hex($ret)."\n";
return $ret=$this->decoderet($ret);
}
//Получить серийный номер
function get_serial()
{
$ret=$this->send_ret("2F");
if(!$ret)return false;
return hexdec(implode("",$ret));
}
//Заряд батареи
function get_battery()
{
$ret=$this->send_ret("29");
if(!$ret)return false;
return implode(".",$ret);
}
//мгновенные значения (U,I,P)
function get_uip()
{
$ret=$this->send_ret("63");
if(!$ret)return false;
$U=$ret[5].$ret[6];
$I=$ret[7].$ret[8];
$P=$ret[9].$ret[10].$ret[11];
//$out['U']=$U[0].$U[1].$U[2].".".$U[3];
$out['U']=(($U[0]*1000.0) + ($U[1]*100.0) + ($U[2]*10.0) + ($U[3]*1.0)) / 10.0;
//$out['mI']=$I[0].$I[1].".".$I[2].$I[3];
$out['mA']=(($I[0]*1000.0) + ($I[1]*100.0) + ($I[2]*10.0) + ($I[3]*1.0)) * 10.0; //вывод значения тока в mA/ч
$out['I']=( (($I[0]*1000.0) + ($I[1]*100.0) + ($I[2]*10.0) + ($I[3]*1.0)) * 10.0 ) / 1000.0; //вывод значения тока в A/ч
//$out['P']=$P[0].$P[1].$P[2].".".$P[3].$P[4].$P[5];
$out['W']=( ($P[0]*100000.0) + ($P[1]*10000.0) + ($P[2]*1000.0) + ($P[3]*100.0) + ($P[4]*10.0) + ($P[5]*1.0) ); //вывод значения мощности в Вт/ч
$out['P']=( ($P[0]*100000.0) + ($P[1]*10000.0) + ($P[2]*1000.0) + ($P[3]*100.0) + ($P[4]*10.0) + ($P[5]*1.0) ) / 1000.0; //вывод значения мощности в кВт/ч
return $out;
}
//значения энергии
function get_values()
{
$ret=$this->send_ret("27");
if(!$ret)return false;
$out[1]=$ret[5].$ret[6].$ret[7].".".$ret[8];
$out[2]=$ret[9].$ret[10].$ret[11].".".$ret[12];
$out[3]=$ret[13].$ret[14].$ret[15].".".$ret[16];
$out[4]=$ret[17].$ret[18].$ret[19].".".$ret[20];
//суммированные значения
$out[0]=$out['1']+$out['2']+$out['3']+$out['4'];
return $out;
}
//Удаляем лишнее из ответа
function decoderet($msg)
{
$len=strlen($msg);
$msg=str_split($msg,2);
$len=count($msg);
if($len<6){$error1="string too small($len <6)\n";return false;}
if($msg[0].$msg[1].$msg[2].$msg[3]!=$this->addr){$error="line is busy\n";return false;}
unset($msg[$len-1],$msg[$len-2],$msg[1],$msg[2],$msg[3],$msg[0],$msg[4]);
return $msg;
}
// Format input string as nice hex
function nice_hex($str) {
return strtoupper(implode(' ',str_split($str,2)));
}
function crc16_modbus($msg)
{
$data = pack('H*',$msg);
$crc = 0xFFFF;
for ($i = 0; $i < strlen($data); $i++)
{
$crc ^=ord($data[$i]);
for ($j = 8; $j !=0; $j--)
{
if (($crc & 0x0001) !=0)
{
$crc >>= 1;
$crc ^= 0xA001;
}
else $crc >>= 1;
}
}
$crc=sprintf('%04X', $crc);
return $crc[2].$crc[3].$crc[0].$crc[1];
}
}
$merc=new mercury206_lib("192.168.3.65","3020","12345678");
echo $error;
echo $error1;
if ($merc->get_serial() !="")
{
echo "Serial number: ".$merc->get_serial()."<br>";
echo "Battery level: ".$merc->get_battery()."<br>";
$uip=$merc->get_uip();
echo "U: ".$uip['U']." I: ".$uip['I']."A/ч"."(".$uip['mA']."mA/ч)"." P: ".$uip['P']."кВт/ч"."(".$uip['W']."Вт/ч)"."<br>";
$values=$merc->get_values();
echo "Power values: all: ".$values[0]." tarif1: ".$values[1]." tarif2: ".$values[2];
sg('Sensor_voltage01.alive',1);
sg('Sensor_power01.alive',1);
sg('Counter03.alive',1);
sg('Counter04.alive',1);
sg('Counter05.alive',1);
sg('Sensor_voltage01.value',$uip['U']);
sg('Sensor_power01.value',$uip['P']*1000);
sg('Counter03.value',$values['0']);
sg('Counter04.value',$values['1']);
sg('Counter05.value',$values['2']);
} else {
echo "Msg is empty";
sg('Sensor_voltage01.alive',0);
sg('Sensor_power01.alive',0);
sg('Counter03.alive',0);
sg('Counter04.alive',0);
sg('Counter05.alive',0);
}
Я создал сценарий mercury и дергаю его по крону раз в пять минут.
Конечно, вы должны в строке
$merc=new mercury206_lib("192.168.3.65","3020","12345678");
указать свой IP-адрес, порт ser2net и номер счетчика, также создать три счетчка-ПУ, ПУ-датчик мощности и ПУ-датчик напряжения, и направить в них данные из скрипта.
Если запустить сценарий вручную, мы должны получить вот такой ответ:
Serial number: 12345678
Battery level: 03.20
U: 230.7 I: 2.04A/ч(2040mA/ч) P: 0.46кВт/ч(460Вт/ч)
Power values: all: 13370.52 tarif1: 008934.61 tarif2: 004435.91
Если не получили, надо смотреть что там на устройстве не так.
Я изменил php-скрипт так, чтобы было видно, что счетчик не отдает данные (свойство alive=0) и чтобы в счетчики не сыпался всякий мусор и нули при ошибках.
Ну, и бонусом, опубликую еще один сценарий, который мне позволяет держать руку на пульсе расходов, потому что у меня электрокотел, который питается исключительно деньгами ))
$price_day = 6.39;
$price_night = 2.41;
$price = 5.56;
$days = date("j");
$days_month = date("t");
$count_day = gg('Counter04.valueMonth');
$count_night = gg('Counter05.valueMonth');
$summa_day = round($count_day*$price_day);
$summa_night = round($count_night*$price_night);
$count = $count_day+$count_night;
$summa = $summa_day+$summa_night;
sg('Counter06.value', $summa);
$summa_old = round(($count_day+$count_night)*$price);
$result =
'<pre>День: '.$count_day.' кВт/ч, '.$summa_day.' руб.'.chr(13).chr(10).
'Ночь: '.$count_night.' кВт/ч, '.$summa_night.' руб.'.chr(13).chr(10).
'Итого: '.$count.' кВт/ч, '.$summa.' руб., (по среднему: '.$summa_old.' руб.)'.chr(13).chr(10).
'В среднем в день: '.round($count/$days).' кВт/ч, '.round($summa/$days).' руб.'.chr(13).chr(10).
'Прогноз: '.round($count/$days)*$days_month.' кВт/ч, '.round($summa/$days*$days_month).' руб.</pre>';
echo $result;
return $result;
Данный скрипт я дергаю также раз в пять минут или из телеграм, а Counter06 - это еще один счетчик с деньгами.
В результате получается какой-то такой ответ
День: 123.78 кВт/ч, 791 руб.
Ночь: 112.55 кВт/ч, 271 руб.
Итого: 236.33 кВт/ч, 1062 руб., (по среднему: 1314 руб.)
В среднем в день: 30 кВт/ч, 133 руб.
Прогноз: 930 кВт/ч, 4115 руб.
после чего можно начинать паниковать, выключать котел и начинать топить печь.
Всем удачи, не болейте и пишите, если есть вопросы или нашли какие-то ошибки!
Москва, Россия