Возвращение к "Меркурию"...

Использование системы в различных ситуациях, вопросы программирования сценариев.

Модератор: immortal

Ответить
Victor_S
Сообщения: 265
Зарегистрирован: Пт дек 26, 2014 1:58 pm
Благодарил (а): 33 раза
Поблагодарили: 24 раза

Возвращение к "Меркурию"...

Сообщение Victor_S » Пн мар 08, 2021 9:48 pm

Приветствую всех!
Да, я знаю о существовании модулей Меркурий и Энергомера...:) И о еще кучи тем об электросчетчиках Меркурий...
Но, все же , позвольте продолжить...
Как мне казалось, я закрыл для себя эту тему еще лет 5 назад. Однако обстоятельства вынудили вернуться к этой теме более углубленно.
В свое время я пытался сам, еще до появления вышеперечисленный модулей, создать модуль для Меркурия 236. Но тогда у меня Majordomo крутился еще под Windows и решить проблему с нормальным(гарантированным) чтением com порта я так и не смог. Плюнул, и реализовал обработку электросчетчиков на микрокомпьютере под linux, со своим LAMP. Из MD просто вызывалась отдельная вэб-страничка, хостящаяся на микрокомпьютере. И все б ничего, но за эти годы я задолбался менять флэшки. Опрос 2-х счетчиков велся в непрерывном цикле и писался в mysql, убивая флэшку за пол-года, год, полтора... В общем достался мне по наследству неттоп на атоме с обычным диском, и я решил заменить им пару микрокомпьютеров выполнявших функции связи с электросчетчиками, метеостанции и MQTT-брокера. Не особо задумываясь о последствиях...;), зашел на сайт ubuntu, и установил последнюю версию сервера(20.04). В комплекте получил php версии 7.4.3... И тут же получил проблемы со "своим" скриптом для электросчетчиков...:( Я не зря слово своим взял в кавычки... Как и подавляющее количество людей, выложивших свои скрипты в сеть(включая и модуль "Меркурий"), ноги у всех растут из одного скрипта с сайта ab-log.ru. Скрипты каждого лишь дополняли и расширяли возможности "базового" , и все без исключения использовали 2 небольшие функции для чтения данных со счетчиков. Вот о них то и пойдет речь... Почему здесь , а не на ab-log.ru? Похоже форум там окончательно умер, увы...:( Более чем неделю назад, я попытался задать вопрос, увы - тишина полная... Довольно лирики... теперь конкретно:
Функций2 и вопросов 2.
Забыл предупредить...:) Я не программист(не кодер) и никогда этим не занимался, но более 20 лет в должности сисадмина на не маленьком предприятии, научили немного логическому мышлению и какому-никакому чтению чужих кодов...:)

1. Функция dd()

Код: Выделить всё

function dd($data = "")
{
$result1 = "";
$data2 = "";
for ( $j = 0; $j < count($data); $j++ )
{
$data2 = dechex(ord($data[0]));
if ( strlen($data2) == 1 )
$result1 = "0".$data2;
else
$result1 .= $data2;

}
return $result1;
}
Вызывается данная функция из второй которые нас интересуют.(К примеру hexdec(dd($result1[2])). Тут можно видеть, что аргументом функции всегда будет один элемент массива - байт. Ну и при объявлении функции мы не видим никакого массива($data = ""). В этом как раз и проявляется проблема в php старше 7-ой версии. Поскольку, функция count при получении не массива выдает ошибку.
Я переписал у себя данную функцию следующим образом:

Код: Выделить всё

function dd($data = "")
{
	$result1 = "";
	$data2 = "";
	if (isset($data) && !empty($data))
//	for ( $j = 0; $j < count2($data); $j++ )
	{
		$data2 = dechex(ord($data[0]));
		if ( strlen($data2) == 1  )
		$result1 = "0".$data2;
		else
		$result1 .= $data2;

	}
	return $result1;
}
Вроде бы все работает, но, как уже писал, не программер я...:). Прошу прокомментировать возможные мои ошибки и как быть в данной ситуации, если я ошибаюсь в своих выводах...
Разбор второй функции оставлю на второй пост ибо и так много буков получилось...
Victor_S
Сообщения: 265
Зарегистрирован: Пт дек 26, 2014 1:58 pm
Благодарил (а): 33 раза
Поблагодарили: 24 раза

Re: Возвращение к "Меркурию"...

Сообщение Victor_S » Пн мар 08, 2021 11:22 pm

Итак, продолжим...
Функция №2:
Название может чутка разниться, но содержание одинаково. Я лишь немного упростил ее, оставив только вариант для RS485, а CAN убрал.

Код: Выделить всё

function merc_rd($result1, $factor = 1, $total = 0)
{

	$ret = array();
	
	if ( $total != 1 )
	{
		for ( $i = 0; $i < 4; $i++ )
		{
			if ( dechex(ord($result1[1 + $i * 3])) >= 40 )
			$result1[1 + $i * 3] = chr(dechex(ord($result1[1 + $i * 3])) - 40);
			if ( strlen($result1) > 3 + $i * 3 )
			$ret[$i] = hexdec(dd($result1[1 + $i * 3]).dd($result1[1 + $i * 3 + 2]).dd($result1[1 + $i * 3 + 1]))*$factor;
		}
	}
	else
	$ret[0] = hexdec(dd($result1[2]).dd($result1[1]).dd($result1[4]).dd($result1[3]))*$factor;


	return $ret;
}
Просматривая некоторые графики, заметил, что иногда значения суммарной мгновенной мощности, что активной, что реактивной, могут значительно превышать сумму значений по фазам.
1.jpg
1.jpg (171.31 КБ) 1196 просмотров
2.jpg
2.jpg (175.21 КБ) 1196 просмотров
У меня закралось подозрение на вот эти строчки функции:

Код: Выделить всё

			if ( dechex(ord($result1[1 + $i * 3])) >= 40 )
			$result1[1 + $i * 3] = chr(dechex(ord($result1[1 + $i * 3])) - 40);
Словно в подтверждение, нашел в ветке по модулю "Меркурий" вот такие сообщения:
3.jpg
3.jpg (249.45 КБ) 1196 просмотров

Код: Выделить всё

function merc_gd($socket252, $cmd, $factor = 1, $total = 0)
{

// Запрашиваем до трех попыток пока не сойдется CRC, если неудачно - прерываем.
$i=0;
do {
	$this->send($socket252, $cmd);
	$result =$this->read($socket252);
	$i++;
} while ((($this->checkCRC($result))==false)&&($i<3));

// Если три попытки неудачны и CRC неверен - прерываем функцию.
if ($i==3) {
	if (($this->checkCRC($result))==false) return;
}

	$ret = array();
	
	$start_byte = 1;
		
	if ( $total != 1 )
	{	
		for ( $i = 0; $i < 4; $i++ )
		{
         	//if ( dechex(ord($result[$start_byte + $i * 3])) >= 40 )
			//$result[$start_byte + $i * 3] = chr(dechex(ord($result[$start_byte + $i * 3])) - 40);
			if ( strlen($result) > $start_byte + 2 + $i * 3 )
				// Для всех запросов кроме мощности используем стандартный рассчет
				if (substr($cmd,2,6)!='081600') {
					$ret[$i] = hexdec($this->dd($result[$start_byte + $i * 3]).$this->dd($result[$start_byte + $i * 3 + 2]).$this->dd($result[$start_byte + $i * 3 + 1]))*$factor;
				}
				// При запросе мощности нужно маскировать два старших разряда старшего бита
				else {
					$hex = $this->dd($result[$start_byte + $i * 3]).$this->dd($result[$start_byte + $i * 3 + 2]).$this->dd($result[$start_byte + $i * 3 + 1]);
					$bin=base_convert($hex, 16, 2);
					// Обрезаем строку до 22 бит
					while (strlen($bin)>22) $bin=substr($bin,1);
					$ret[$i] = bindec($bin)*$factor;
				}
		}
		
	}
	else
		$ret[0] = hexdec($this->dd($result[$start_byte+1]).$this->dd($result[$start_byte]).$this->dd($result[$start_byte+3]).$this->dd($result[$start_byte+2]))*$factor;
	return $ret;
}
Однако у меня показания мощности реальные, лишь иногда бывают непонятные "выбросы" полной суммарной мощности... Кто подскажет, где тут собака зарыта? Напомню, у меня счетчики не 230, а 236. Хотя все команды идентичны.
Ответить