Передача Счетчиков

«ПульсХАБ» поддерживает передачу статистики каналов по LAN интерфейсу в формате CSV.

Приведена строка 1 канала с режимом работы счета времени (2), коэффициенте пересчета 1, названием единиц счета в секундах, показаниями сбрасываемого и общего счетчиков, датами изменения показания, сброса и установки и текста описания канала
01;2;1;сек;119020;119951;;;10/06/13 10:37:28;04/06/13 00:51:42;04/06/13 00:35:45;Счетчик времени

Подробное описание строки содержится в руководстве по эксплуатации «ПульсХАБ».

Принятые показания счетчиков можно передать в базу данных, использовать для on-line мониторинга и т.д.

Рассмотрим пример Perl-скрипта для приема статистики каналов и записи в базу данных.

В начале скрипта константами задаются IP адрес прибора, порт подключения и HTTP строки запросов. Они могут быть изменены в зависимости от настроек прибора.

В первую очередь из прибора запрашивается серийный номер, затем текущая статистика каналов. Обязательно надо проверять результаты запросов.

Создание файла базы данных SQLite выполняется автоматически. Для этого примера возможно выбрать другую SQL совместимую базу данных, указав расположение сервера и параметры входа. Если таблица отсутствует в базе данных, то она создается с заданными параметрами полей.

Принятая статистика в формате CSV в кодировке CP1251 разбивается на строки. Каждая строка разбивается символом ';' на поля. После проверки полей на целочисленные значения, режима работы канала, преобразования кодировки строк и показаний единиц счета к единицам измерения выполняется запись в базу данных.

После обработки всех строк завершаются запрос и соединение с базой данных.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#!/bin/perl -w
#
# прием показаний счетчиков от прибора «ПульсХАБ» и передача в базу данных SQLite
#
# http://tigra-electronic.com/products/pulsehub.htm
# 10/06/2013
 
use strict;
use LWP::UserAgent;
use HTTP::Request;
use DBI;
use Encode qw(decode);
 
use constant IP_AND_PORT	=> '192.168.0.90:80';
use constant {
	GET_ID					=> 'http://'.IP_AND_PORT.'/id.xml',				# строка запроса серийного номера прибора
	GET_CHANNELS_UNITS		=> 'http://'.IP_AND_PORT.'/channels.cgi?t=b1&f=c'	# строка запроса данных с единицами измерений без пересчета
};
 
sub date {			# функция преобразования даты, 20/02/12 12:31 => 2012/02/20 12:31
	return ( shift =~ /(\d+)\/(\d+)\/(\d+) ([\d:]+)/ && $3 != 0 ) ? (2000+$3)."/$2/$1 $4" : undef;	# если в позиции года 00, значит время неопределено
}
 
	my $ua = LWP::UserAgent->new();	# подготовка подключения
	$ua->credentials(				# установки подключения
		IP_AND_PORT,
		'Protected',
		'guest' => 'guest'			# логин и пароль (рекомендуется указывать гостевую учетную запись)
	);
 
	my $request = HTTP::Request->new(GET => GET_ID);	# подготовка запроса серийного номера прибора
	my $result = $ua->request( $request );					# выполнение запроса
	if( !$result->is_success ) {							# проверка наличия ответа
		die "error: request serial number [".$result->status_line."]\n";
	}
 
	$result->content =~ /<serial>(\d+)<\/serial>/		# проверка присутствия строки с серийным номером
		|| die "error: invalid serial number\n";	 	# и выдача ошибки, если строка отсутствует
	my $sn = int($1);							# преобразование строки в числовое значение
 
	$request = HTTP::Request->new(GET => GET_CHANNELS_UNITS);	# подготовка запроса данных с единицами измерений
	$result = $ua->request( $request );							# выполнение запроса
	if( !$result->is_success ) {								# проверка наличия ответа
		die "error: request channels [".$result->status_line."]\n";
	}
 
	my $dbh = DBI->connect("dbi:SQLite:dbname=pulsehub_data.db","","");	# соединение с базой данных SQL в файле
 
	$dbh->do("CREATE TABLE IF NOT EXISTS tbl_channels ("		# если таблица отсутствует, создается новая таблица с нижеприведенными полями
		."id INTEGER PRIMARY KEY,"		# идентификатор записи в базе данных
		."int_sn INTEGER,"				# серийный номер прибора
		."int_channel INTEGER,"			# номер канала прибора
		."text_note TEXT,"				# описание канала
		."int_mode INTEGER,"			# режим работы канала
		."text_unit TEXT,"				# строка с единицами измерения канала
		."float_ratio REAL,"			# коэффициент пересчета
		."date_set DATETIME,"			# дата установки канала
		."int_counts_total INTEGER,"	# показание общего счетчика в единицах счета
		."float_value_total INTEGER,"	# показание общего счетчика в единицах измерения
		."date_value DATETIME,"			# дата изменения счетчика
		."date_record DATETIME DEFAULT CURRENT_TIMESTAMP"	# дата записи в базу данных, заполняется по умолчанию
		.")");
 
	my $sth = $dbh->prepare("INSERT INTO tbl_channels (int_sn,int_channel,text_note,int_mode,text_unit,float_ratio,int_counts_total,float_value_total,date_set,date_value)"
		."VALUES(?,?,?,?,?,?,?,?,?,?)");	# подготовка запроса в базу данных
 
	my $i = 0;	# количество выполненных записей
	foreach my $s (split "\n", $result->content) {		# разделение строк и цикл обработки для каждой строки
		my ($channel, $mode, $ratio, $unit, $counts, $counts_total, $min, $max, $date_value, $date_reset, $date_set, $note) = split(';', $s);	# разделение на поля
		my $value_total;
		if( $mode =~ /\d+/ && $counts =~ /\d+/ && $ratio =~ /\d+/ && $channel =~ /\d+/ ) {	# проверка полей на целочисленные значения
			$mode = int($mode);
			if( $mode != 0 ) {					# выключенные каналы не записываются
				$channel = int($channel);
				$counts_total = int($counts_total);
				$note = decode("cp1251", $note);	# преобразование строки в UTF-8
				$unit = decode("cp1251", $unit);
				$ratio = int($ratio);
				$value_total = ($ratio != 0) ? $counts_total / $ratio : undef;		# если коэффициент пересчета 0, тогда значение будет неопределенным
				$sth->execute($sn,$channel,$note,$mode,$unit,$ratio,$counts_total,$value_total,date($date_set),date($date_value));	# занесение записи в базу данных
				$i++;
			}
		} else {
			print "warning: invalid fields for [$sn]->$channel\n";
		}
	}
	$sth->finish();			# завершение запроса
	$dbh->disconnect();		# отключение от базы данных
	print "Query complete! $i records inserted.\n"