diff --git a/AttributesSample/LersSample.csproj b/AttributesSample/LersSample.csproj
new file mode 100644
index 0000000..b3e8686
--- /dev/null
+++ b/AttributesSample/LersSample.csproj
@@ -0,0 +1,81 @@
+
+
+
+ Debug
+ x86
+ 8.0.30703
+ 2.0
+ {1E9BFBEA-6183-416C-B5EA-C883CD62277E}
+ Exe
+ Properties
+ LersSample
+ LersSample
+ v4.0
+ Client
+ 512
+
+
+ x86
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ false
+
+
+ x86
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ false
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE
+ full
+ x64
+ false
+ prompt
+ false
+ false
+
+
+ bin\x64\Release\
+ TRACE
+ true
+ pdbonly
+ x64
+ false
+ prompt
+
+
+
+ False
+ ..\..\Lers.System\bin\x64\Debug\Lers.System.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AttributesSample/LersSample.sln b/AttributesSample/LersSample.sln
new file mode 100644
index 0000000..043b7a5
--- /dev/null
+++ b/AttributesSample/LersSample.sln
@@ -0,0 +1,26 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LersSample", "LersSample.csproj", "{1E9BFBEA-6183-416C-B5EA-C883CD62277E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1E9BFBEA-6183-416C-B5EA-C883CD62277E}.Debug|x64.ActiveCfg = Debug|x64
+ {1E9BFBEA-6183-416C-B5EA-C883CD62277E}.Debug|x64.Build.0 = Debug|x64
+ {1E9BFBEA-6183-416C-B5EA-C883CD62277E}.Debug|x86.ActiveCfg = Debug|x86
+ {1E9BFBEA-6183-416C-B5EA-C883CD62277E}.Debug|x86.Build.0 = Debug|x86
+ {1E9BFBEA-6183-416C-B5EA-C883CD62277E}.Release|x64.ActiveCfg = Release|x86
+ {1E9BFBEA-6183-416C-B5EA-C883CD62277E}.Release|x64.Build.0 = Release|x86
+ {1E9BFBEA-6183-416C-B5EA-C883CD62277E}.Release|x86.ActiveCfg = Release|x86
+ {1E9BFBEA-6183-416C-B5EA-C883CD62277E}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/AttributesSample/Program.cs b/AttributesSample/Program.cs
new file mode 100644
index 0000000..fd5e476
--- /dev/null
+++ b/AttributesSample/Program.cs
@@ -0,0 +1,126 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Security;
+using Lers.Core;
+using Lers.Data;
+
+namespace LersSample
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ // Создаем экземпляр объекта LersServer, через который осуществляется работа с сервером ЛЭРС УЧЕТ.
+
+ Lers.LersServer server = new Lers.LersServer();
+
+ // Создаем данные для авторизации в системе (логин и пароль).
+
+ string login = "admin";
+ SecureString password = Lers.Networking.SecureStringHelper.ConvertToSecureString("admin");
+
+ Lers.Networking.BasicAuthenticationInfo authInfo = new Lers.Networking.BasicAuthenticationInfo(login, password);
+
+ // Выполняем подключение к серверу, указывая имя компьютера и TCP-порт, а так же данные для авторизации.
+
+ try
+ {
+ server.Connect("localhost", 10000, authInfo);
+ }
+ catch (Exception exc)
+ {
+ Console.WriteLine("Ошибка подключения к серверу.\r\n" + exc.Message);
+ Console.Read();
+ return;
+ }
+
+ Console.WriteLine("Версия сервера: " + server.Version.ToString());
+
+ // Получаем объект учета по уникальному номеру, который задается в свойствах объекта учета.
+ // Указываем через флаг, что нам нужны атрибуты и системы объекта учета.
+ Node node = server.Nodes.GetByNumber(1232, NodeInfoFlags.Attributes | NodeInfoFlags.Systems);
+
+ // Убеждаемся, что мы получили указатель на объект Node.
+ // Если объект учета с таким номером не существует или он недоступна для текущего пользовтеля, то метод GetByNumber() вернет null.
+
+ if (node != null)
+ {
+ // Выводим наименование Объекта учета.
+
+ Console.WriteLine("Объект учета \'{0}\'", node.Title);
+
+ MeasurePoint[] measurePoints = node.Systems.HotWater.MeasurePoints.ToArray();
+
+ // Запрашиваем данные о суточном потреблении гвс за двое суток.
+
+ MeasurePointConsumptionRecord[] consumption1 = measurePoints[0].Data.GetConsumption(DateTime.Today.AddDays(-1), DateTime.Today, Lers.Data.DeviceDataType.Day).ToArray();
+
+ MeasurePointConsumptionRecord[] consumption2 = measurePoints[1].Data.GetConsumption(DateTime.Today.AddDays(-1), DateTime.Today, Lers.Data.DeviceDataType.Day).ToArray();
+
+ string scheme = (string)node.Attributes["схема"];
+
+ MeasurePointConsumptionRecord[] consumption = new MeasurePointConsumptionRecord[consumption1.Length];
+
+ switch (scheme)
+ {
+ // Первая схема измерения
+ case "1":
+
+ // Здесь реализуем расчет по схеме измерения, например складываем потребления по двум точкам учета.
+
+ for (int i = 0; i < consumption1.Length; i++)
+ {
+ MeasurePointConsumptionRecordWater record = new MeasurePointConsumptionRecordWater(consumption1[i].DateTime);
+
+ record.M_in = ((MeasurePointConsumptionRecordWater)consumption1[i]).M_in + ((MeasurePointConsumptionRecordWater)consumption2[i]).M_in;
+ record.M_out = ((MeasurePointConsumptionRecordWater)consumption1[i]).M_out + ((MeasurePointConsumptionRecordWater)consumption2[i]).M_out;
+
+ consumption[i] = record;
+ }
+
+ break;
+
+ // Вторая схема измерения
+ case "2":
+
+ // Здесь реализуем расчет по схеме измерения, например вычисляем разницу потребления по двум точкам учета.
+
+ for (int i = 0; i < consumption1.Length; i++)
+ {
+ MeasurePointConsumptionRecordWater record = new MeasurePointConsumptionRecordWater(consumption1[i].DateTime);
+
+ record.M_in = ((MeasurePointConsumptionRecordWater)consumption1[i]).M_in - ((MeasurePointConsumptionRecordWater)consumption2[i]).M_in;
+ record.M_out = ((MeasurePointConsumptionRecordWater)consumption1[i]).M_out - ((MeasurePointConsumptionRecordWater)consumption2[i]).M_out;
+
+ consumption[i] = record;
+ }
+
+ break;
+
+ default:
+ throw new Exception("Неподдерживаемый номер схемы измерения.");
+ }
+
+ // Выводим данные на экран.
+
+ foreach (MeasurePointConsumptionRecordWater recordWater in consumption)
+ {
+ Console.WriteLine("{0}: M1 = {1}, M2 = {2}", recordWater.DateTime, recordWater.M_in, recordWater.M_out);
+ }
+ }
+ else
+ {
+ Console.WriteLine("Объект учета не существует или недоступен для данной учетной записи.");
+ }
+
+ Console.ReadLine();
+
+ // Отключаемся от сервера.
+ // Указываем таймаут 2 секунды на нормальное завершение сеанса, после выхода которого, соединение будет разорвано.
+
+ server.Disconnect(2000);
+ }
+ }
+}
diff --git a/AttributesSample/Properties/AssemblyInfo.cs b/AttributesSample/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..49ac514
--- /dev/null
+++ b/AttributesSample/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("LersSample")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("LersSample")]
+[assembly: AssemblyCopyright("Copyright © 2013")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("6a23aa78-7b98-4b51-bad6-69ea6363f58c")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/GetDataSample/LersSample.csproj b/GetDataSample/LersSample.csproj
new file mode 100644
index 0000000..bc881c9
--- /dev/null
+++ b/GetDataSample/LersSample.csproj
@@ -0,0 +1,60 @@
+
+
+
+ Debug
+ x86
+ 8.0.30703
+ 2.0
+ {1E9BFBEA-6183-416C-B5EA-C883CD62277E}
+ Exe
+ Properties
+ LersSample
+ LersSample
+ v4.0
+ Client
+ 512
+
+
+ x86
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ false
+
+
+ x86
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ false
+
+
+
+ ..\..\Lers.System\bin\x86\Release\Lers.System.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GetDataSample/LersSample.sln b/GetDataSample/LersSample.sln
new file mode 100644
index 0000000..60a22e3
--- /dev/null
+++ b/GetDataSample/LersSample.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LersSample", "LersSample.csproj", "{1E9BFBEA-6183-416C-B5EA-C883CD62277E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x86 = Debug|x86
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1E9BFBEA-6183-416C-B5EA-C883CD62277E}.Debug|x86.ActiveCfg = Debug|x86
+ {1E9BFBEA-6183-416C-B5EA-C883CD62277E}.Debug|x86.Build.0 = Debug|x86
+ {1E9BFBEA-6183-416C-B5EA-C883CD62277E}.Release|x86.ActiveCfg = Release|x86
+ {1E9BFBEA-6183-416C-B5EA-C883CD62277E}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/GetDataSample/Program.cs b/GetDataSample/Program.cs
new file mode 100644
index 0000000..e13939c
--- /dev/null
+++ b/GetDataSample/Program.cs
@@ -0,0 +1,109 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Security;
+using Lers.Core;
+using Lers.Data;
+
+namespace LersSample
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ // Создаем экземпляр объекта LersServer, через который осуществляется работа с сервером ЛЭРС УЧЕТ.
+
+ Lers.LersServer server = new Lers.LersServer();
+
+ // Создаем данные для авторизации в системе (логин и пароль).
+
+ string login = "Admin";
+ SecureString password = Lers.Networking.SecureStringHelper.ConvertToSecureString("admin");
+
+ Lers.Networking.BasicAuthenticationInfo authInfo = new Lers.Networking.BasicAuthenticationInfo(login, password);
+
+ // Выполняем подключение к серверу, указывая имя компьютера и TCP-порт, а так же данные для авторизации.
+
+ try
+ {
+ server.Connect("localhost", 10000, authInfo);
+ }
+ catch (Exception exc)
+ {
+ Console.WriteLine("Ошибка подключения к серверу.\r\n" + exc.Message);
+ Console.Read();
+ return;
+ }
+
+ Console.WriteLine("Версия сервера: " + server.Version.ToString());
+
+ // Получаем точку учета по уникальному номеру, который задается в свойствах точки учета.
+
+ MeasurePoint measurePoint = server.MeasurePoints.GetByNumber(123);
+
+ // Убеждаемся, что мы получили указатель на объект MeasurePoint.
+ // Если точки учета с таким номером не существует или она недоступна для текущего пользовтеля, то метод GetByNumber() вернет null.
+
+ if (measurePoint != null)
+ {
+ // Выводим полное наименование точки учета.
+
+ Console.WriteLine("Точка учета \'{0}\'", measurePoint.FullTitle);
+
+ if (measurePoint.SystemType != SystemType.Gas)
+ {
+ Console.WriteLine("Точка учета должна иметь систему Газонабжение.");
+ Console.Read();
+ return;
+ }
+
+ // Сохраняем суточные данные о потреблении по точке учета.
+ // Чтобы сохранить данные по воде, используйте Lers.Data.WaterConsumptionRecord, по электроэнергии - Lers.Data.ElectricConsumptionRecord.
+
+ MeasurePointConsumptionRecordCollection data = new MeasurePointConsumptionRecordCollection(DeviceDataType.Day);
+
+ MeasurePointConsumptionRecordGas record = new MeasurePointConsumptionRecordGas(DateTime.Today.AddDays(-1)); // За вчерашние сутки
+ record.V = 100; // Объем газа
+ record.T = 20; // Температура газа
+
+ data.Add(record);
+
+ MeasurePointConsumptionRecordGas record2 = new Lers.Data.MeasurePointConsumptionRecordGas(DateTime.Today); // За сегодняшние сутки
+ record2.V = 80; // Объем газа
+ record2.T = 15; // Температура газа
+
+ data.Add(record2);
+
+ // Устанавливаем флаг для перезаписи существующих данных и сохраняем данные.
+
+ MeasurePointSetConsumptionOptions options = new MeasurePointSetConsumptionOptions();
+ options.OverwriteExistingRecords = true;
+
+ measurePoint.Data.SetConsumption(data, options);
+
+ // Запрашиваем данные о суточном потреблении газа за двое суток.
+
+ MeasurePointConsumptionRecordCollection consumption = measurePoint.Data.GetConsumption(DateTime.Today.AddDays(-1), DateTime.Today, Lers.Data.DeviceDataType.Day);
+
+ // Выводим данные на экран.
+
+ foreach (MeasurePointConsumptionRecordGas recordGas in consumption)
+ {
+ Console.WriteLine("{0}: V = {1}, T = {2}", recordGas.DateTime, recordGas.V, recordGas.T);
+ }
+ }
+ else
+ {
+ Console.WriteLine("Точка учета не существует или недоступна для данной учетной записи.");
+ }
+
+ Console.ReadLine();
+
+ // Отключаемся от сервера.
+ // Указываем таймаут 2 секунды на нормальное завершение сеанса, после выхода которого, соединение будет разорвано.
+
+ server.Disconnect(2000);
+ }
+ }
+}
diff --git a/GetDataSample/Properties/AssemblyInfo.cs b/GetDataSample/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..49ac514
--- /dev/null
+++ b/GetDataSample/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("LersSample")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("LersSample")]
+[assembly: AssemblyCopyright("Copyright © 2013")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("6a23aa78-7b98-4b51-bad6-69ea6363f58c")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/ImportTemperature/ImportTemperature.docx b/ImportTemperature/ImportTemperature.docx
new file mode 100644
index 0000000..476d6c8
--- /dev/null
+++ b/ImportTemperature/ImportTemperature.docx
@@ -0,0 +1,22 @@
+Назначение
+ Скрипт ImportTemperature.ps1 выполняет импорт данных среднесуточной температуры наружного воздуха с сайта мониторинга погоды www.pogoda.ru.net [HYPERLINK: http://www.pogoda.ru.net] в ЛЭРС УЧЕТ. Импортированные данные сохраняются в справочник температур наружного воздуха.
+
+Синтаксис
+ Powershell .\ImportTemperature.ps1 Город [период]
+ где:
+ Город - название города, по которому необходимо импортировать данные среднесуточной температуры. Параметр должен быть первым в параметрах командной строки.
+ [период] - интервал времени в формате <дата_начала>-< дата_окончания>, за который импортируются данные среднесуточной температуры. Если параметр не указан, то импортируются данные за предыдущий день. Даты начала и окончания периода задаются в формате dd.mm.yyyy.
+
+Пример 1. Импорт данных среднесуточной температуры за предыдущий день в Хабаровске.
+ Powershell .\ImportTemperature.ps1 "Хабаровск"
+
+Пример 2. Импорт данных среднесуточной температуры с 1 декабря по 10 декабря в Хабаровске.
+ Powershell .\ImportTemperature.ps1 "Хабаровск" "01.12.2010-10.12.2010"
+
+Параметры
+Перед первым запуском импорта данных необходимо настроить параметры импорта, которые задаются в тексте самого скрипта.
+$LersAutoPath - расположение файла сервера автоматизации
+$ServerAddress - адрес сервера ЛЭРС УЧЕТ. В качестве адреса сервера может быть указано как имя, так и IP-адрес компьютера, на котором установлен сервер
+$ServerPort - порт сервера ЛЭРС УЧЕТ
+$Login - Имя входа в ЛЭРС УЧЕТ
+$PassWord - пароль для входа в ЛЭРС УЧЕТ
diff --git a/ImportTemperature/ImportTemperature.ps1 b/ImportTemperature/ImportTemperature.ps1
new file mode 100644
index 0000000..ec4626f
--- /dev/null
+++ b/ImportTemperature/ImportTemperature.ps1
@@ -0,0 +1,405 @@
+
+ ########################################################################
+ # Настройки
+ ########################################################################
+
+ # путь к фреймворку ЛЭРС УЧЕТ
+ $LersFrameworkPath = "C:\Program Files\LERS\Common\Framework\bin\Lers.System.dll"
+
+ # Адрес сервера приложения
+ $ServerAddress = 'localhost'
+
+ # Порт сервера приложения
+ $ServerPort = 10000
+
+ # Имя входа/пароль для подключения к Серверу
+ $Login = 'login'
+ $PassWord = 'password'
+
+ # адрес ресурса
+ $url = 'http://www.pogoda.ru.net/monitor.php'
+
+ # регулярное выражение, для нахождения url адреса заданного города
+ # Хабаровск
+ $regExpressionCityFirst = '(?i:'
+ $regExpressionCitySecond = ')'
+
+ # регулярное выражение для поиска среднесуточной температуры
+ #
5 | -21.0 | -15.1 |
+ $regExpressionTemperatureFirst = '(?i:'
+ $regExpressionTemperatureSecond = ' | \s*[\d\.\-\+]+ | \s*([\d\.\-\+]+) | )'
+
+ ##################################################################
+ # Подключаемые типы
+ ##################################################################
+
+ try
+ {
+ # подключаем фреймворк
+ add-type -path $LersFrameworkPath
+ }
+ catch
+ {
+ write-host 'Ошибка. Не удалось загрузить файл Lers.System.dll. Проверьте правильность расположения файла. ' + $Error[0].Exception.Message
+ exit
+ }
+
+ ########################################################################
+ # Функции
+ ########################################################################
+
+ # Проверяет заданы ли параметры настройки скрипта
+ Function CheckParameters($url, $ServerAddress, $ServerPort, $Login, $PassWord)
+ {
+ try
+ {
+ if ($url -eq '')
+ {
+ throw new-object Exception('Адрес сайта мониторинга погоды не задан.')
+ }
+
+ if ($ServerAddress -eq '')
+ {
+ throw new-object Exception('Адрес сервера ЛЭРС УЧЕТ не задан.')
+ }
+
+ if (($ServerPort -eq $null) -or ($ServerPort -eq 0) -or ($ServerPort -eq ''))
+ {
+ throw new-object Exception('Порт сервера ЛЭРС УЧЕТ не задан.')
+ }
+
+ if ($Login -eq '')
+ {
+ throw new-object Exception('Имя входа в ЛЭРС УЧЕТ не задано.')
+ }
+
+ if ($PassWord -eq '')
+ {
+ throw new-object Exception('Пароль для входа в ЛЭРС УЧЕТ не задан.')
+ }
+ }
+ catch
+ {
+ throw new-object Exception('Параметры скрипта не настроены. ', $Error[0].Exception)
+ }
+ }
+
+ ##################################################################
+
+ # возвращает содержимое html страницы по адресу url ввиде строки
+ Function Get-WwwString([string]$url, [string]$Encoding = "windows-1251")
+ {
+ try
+ {
+ # создаем web client
+ $wc = new-object System.Net.WebClient
+
+ # устанавливаем кодировку
+ $wc.Encoding = [System.Text.Encoding]::GetEncoding($Encoding)
+
+ # возвращаем html страницу ввиде строки
+ return $wc.DownloadString($url)
+ }
+ catch
+ {
+ throw new-object Exception('Не удалось загрузить html страницу по адресу ' + $url + '.', $Error[0].Exception)
+ }
+ }
+
+ ##################################################################
+
+ # возращает описание исключений
+ Function GetFullExceptionMessage([Exception]$exc)
+ {
+ if($exc -eq $null)
+ {
+ return ''
+ }
+
+ $msg = $exc.Message
+
+ if ($exc.InnerException -ne $null)
+ {
+ $mes = GetFullExceptionMessage $exc.InnerException
+ $msg = $msg + ' ' + $mes
+ }
+
+ return $msg
+ }
+
+ ##########################################################################
+
+ # возвращает url адрес на страницу заданного города
+ # $reply - содержимое html страницы ввиде строки
+ # $gorod - имя города
+ # $url - адрес страницы мониторинга погоды
+ Function Get-CityUrl($reply, $gorod, $url)
+ {
+ try
+ {
+ # регулярное выражение, для нахождения url адреса заданного города
+ # Хабаровск
+ [regex]$reg = $regExpressionCityFirst + $gorod + $regExpressionCitySecond
+ $match = $reg.match($reply)
+
+ if(!$match.Success)
+ {
+ throw new-object Exception(' Url страницы не найден.')
+ }
+
+ # формируем ссылку на страницу
+ $uri = new-object Uri ($url)
+ $urlCity = $match.Groups[1].value
+ $urlCity = 'http://' + $uri.Host + '/' + $urlCity
+
+ return $urlCity
+ }
+ catch
+ {
+ throw new-object Exception('Не удалось получить ссылку на страницу города - ' + $gorod + '.', $Error[0].Exception)
+ }
+ }
+
+ ##########################################################################
+
+ # возвращает хеш-таблицу среднесуточной температуры наружного воздуха за указанный период времени
+ # dateFrom - дата начало периода
+ # dateTo - дата окончания периода
+ # link - url города
+ Function Get-CityTemperature($dateFrom, $dateTo, $link)
+ {
+ try
+ {
+ $today = [DateTime]::Today
+ if($dateFrom -gt $today)
+ {
+ throw new-object Exception('Дата начала периода превышает текущую.')
+ }
+
+ if($dateFrom -gt $dateTo)
+ {
+ throw new-object Exception('Дата начала периода больше даты окончания.')
+ }
+
+ if($dateTo -gt $today)
+ {
+ $dateTo = $today
+ }
+
+ # хеш таблица для хранения среднесуточных значениий температур по дате
+ $TempTable = @{}
+
+ # месяц, за который загружается html-страница с темпераиурами
+ $month = 0
+
+ # html страница
+ [void][string]$html
+
+ while ($dateFrom -le $dateTo)
+ {
+ if ($dateFrom.Month -ne $month)
+ {
+ $month = $dateFrom.Month
+
+ # ссылка на страницу за указанный месяц и год
+ $ref = $link + '&month=' + $dateFrom.Month + '&year=' + $dateFrom.Year
+
+ # загружаем html страницу заданного месяца и года
+ $html = Get-WwwString $ref
+ }
+
+ # регулярное выражение для поиска среднесуточной температуры
+ # 5 | -21.0 | -15.1 |
+ [regex]$reg = $regExpressionTemperatureFirst + $dateFrom.Day + $regExpressionTemperatureSecond
+ $match = $reg.match($html)
+
+ if (!$match.Success)
+ {
+ # температура не найдена
+ throw new-object Exception('Температура не найдена.')
+ }
+
+ # считываем температуру
+ $T = $match.Groups[1].value
+
+ # сохраняем температуру
+ $TempTable[$dateFrom.ToString()] = $T
+
+ $dateFrom = $dateFrom.AddDays(1)
+ }
+
+ return $TempTable
+ }
+ catch
+ {
+ throw new-object Exception('Ошибка получения среднесуточной температуры за указанный период. ', $Error[0].Exception)
+ }
+ }
+
+ ##########################################################################
+
+ # возвращает входные параметры
+ Function Arguments($inArgs)
+ {
+ try
+ {
+ # проверяем количество параметров
+
+ if($inArgs.Length -eq 0)
+ {
+ throw new-object Exception('Отсутствуют параметры командной строки.')
+ }
+
+ # возвращает введенное имя города
+ $gorod = $inArgs[0]
+ $gorod
+
+ [DateTime]$dateTo = [System.DateTime]::Today.AddDays(-1)
+ [DateTime]$dateFrom = $dateTo
+
+
+ if($inArgs.Length -eq 2)
+ {
+ $DateTimeStr = $inArgs[1]
+ $DateTimeStr = $DateTimeStr.Split('-', [System.StringSplitOptions]::RemoveEmptyEntries)
+
+ if($DateTimeStr.Length -ne 2)
+ {
+ throw new-object Exception('Период времени задан неверно.')
+ }
+
+ # дата начало периода
+ if (![DateTime]::TryParse($DateTimeStr[0], [ref]$dateFrom))
+ {
+ throw new-object Exception('Дата начала периода задана в неверном формате. Формат даты: dd.mm.yyyy')
+ }
+
+
+ # дата конца периода
+ if (![DateTime]::TryParse($DateTimeStr[1], [ref]$dateTo))
+ {
+ throw new-object Exception('Дата окончания периода задана в неверном формате. Формат даты: dd.mm.yyyy')
+ }
+ }
+
+
+ # возвращаем дату начало/конца
+ $dateFrom
+ $dateTo
+ }
+ catch
+ {
+ throw new-object Exception('Ошибка разбора параметров коммандной строки. ', $Error[0].Exception)
+ }
+ }
+
+ ##########################################################################
+
+ # Функция подключается к серверу автоматизации и возвращает объект сервера
+ Function ConnectToServer()
+ {
+ try
+ {
+ Write-Host 'подключаемся к серверу по адресу ' $ServerAddress ':' $ServerPort
+
+ $securePassword = [Lers.Networking.SecureStringHelper]::ConvertToSecureString($PassWord)
+
+ $authenticationInfo = New-Object Lers.Networking.BasicAuthenticationInfo($Login, $securePassword)
+
+ # подключаемся к серверу
+ $server = new-object Lers.LersServer
+
+ $server.Connect($ServerAddress, $ServerPort, $authenticationInfo)
+ return $server
+ }
+ catch
+ {
+ throw new-object Exception('Не удалось подключится к серверу ЛЭРС УЧЕТ. ', $Error[0].Exception)
+ }
+ }
+
+ ##########################################################################
+
+ # функция сохраняет данные о температуре на сервере ЛЭРС УЧЕТ
+ # $server - сервер автоматизации
+ # $tempTable - таблица среднесуточных температур
+ Function SaveTemperatureToServer ($server, $tempTable)
+ {
+ Write-Host 'Cохраняем данные на сервере ЛЭРС УЧЕТ'
+ try
+ {
+ $str =''
+ $keys = $tempTable.Keys
+
+ $temperature = New-Object Lers.Data.OutdoorTemperatureRecord[] $keys.Count
+ $i = 0
+
+ foreach($key in $keys)
+ {
+ $dt = [DateTime]::Parse($key)
+
+ $value = [string]$tempTable[$key]
+
+ $separator = [System.Globalization.CultureInfo]::CurrentCulture.NumberFormat.NumberDecimalSeparator;
+
+ $value = [Convert]::ToSingle($value.Replace(".",$separator))
+
+ $record = New-Object Lers.Data.OutdoorTemperatureRecord($dt)
+ $record.Value = $value
+
+ $temperature[$i] = $record
+
+ $i++
+ }
+
+ # сохранение данных на сервере
+ $server.OutdoorTemperature.Set($temperature)
+ }
+ catch
+ {
+ throw new-object Exception('Не удалось сохранить данные среднесуточной температуры на сервере ЛЭРС учет. ', $Error[0].Exception)
+ }
+ }
+
+ ##########################################################################
+ # Точка входа
+ ##########################################################################
+
+ try
+ {
+ Write-Host 'Запуск импорта данных среднесуточной температуры с сайта мониторинга погоды.'
+
+ # проверяем параметры настройки скрипта
+ CheckParameters $url $ServerAddress $ServerPort $Login $PassWord
+
+ #param[0] = город, param[1] = дата_начала, param[2] = дата_окончания
+ [object[]]$param = Arguments $Args
+
+ Write-host 'Загружаем ресурс ' $url
+
+ # загружаем html страницу
+ $reply = Get-WwwString $url
+
+ # получаем ссылку на страницу, указанного города
+ $link = Get-CityUrl $reply $param[0] $url
+
+ # загружаем таблицу с температурами наружного воздуха
+ $tempTable = Get-CityTemperature $param[1] $param[2] $link
+
+ write-host 'Получены среднесуточные температуры.'
+
+ # подключаемся к серверу ЛЭРС
+ $server = ConnectToServer
+
+ # сохраняем температуру на сервере
+ SaveTemperatureToServer $server $tempTable
+
+ Write-Host 'Импорт температур успешно завершен.'
+ }
+ catch
+ {
+ write-host 'Ошибка импорта температур. ' (GetFullExceptionMessage $Error[0].Exception)
+ exit
+ }
+
+ ########################################################################
\ No newline at end of file
diff --git a/KhvAdmDataAdapter/App_Code/Handler.cs b/KhvAdmDataAdapter/App_Code/Handler.cs
new file mode 100644
index 0000000..60ceea8
--- /dev/null
+++ b/KhvAdmDataAdapter/App_Code/Handler.cs
@@ -0,0 +1,486 @@
+using System;
+using System.Collections.Specialized;
+using System.Configuration;
+using System.IO;
+using System.Text;
+using System.Web;
+using Lers.Data;
+using Lers.Core;
+using Lers.Utils;
+
+namespace Lers.Web.DataAdapter.KhvAdm
+{
+ ///
+ /// Реализует обработчик запроса на выдачу данных в формате экспорта, утвержденном администрацией г. Хабаровск
+ ///
+ internal class Handler: IHttpHandler
+ {
+ ///
+ /// Используется в качестве источника при протоколировании.
+ ///
+ private static readonly string CLASS_NAME = typeof(Handler).FullName;
+
+ ///
+ /// Начальная дата для экспорта данных
+ /// Берется из параметра dateFrom
+ ///
+ private DateTime beginDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
+
+ ///
+ /// Конечная дата для экспорта данных
+ /// Берется из параметра dateTo
+ ///
+ private DateTime endDate = DateTime.Now;
+
+ /// Тип временных меток: 1 - часовые, 0 - суточные; -1 - и часовые и суточные
+ private int dataPeriodType = 0;
+
+ ///
+ /// Экземпляр класса для подключения к серверу ЛЭРС УЧЕТ
+ ///
+ private LersServer server;
+
+ ///
+ /// Протоколирует в файл
+ ///
+ private Logger logger;
+
+ ///
+ /// Возвращает значение, позволяющее определить, может ли другой запрос использовать экземпляр класса IHttpHandler.
+ ///
+ bool IHttpHandler.IsReusable
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Получает информацию о запросе
+ ///
+ /// Информация о запросе
+ private string GetRequestInfo()
+ {
+ if (HttpContext.Current == null || HttpContext.Current.Request == null)
+ return "<Не удалось получить дополнительную информацию о запросе>";
+
+ HttpRequest currentRequest = HttpContext.Current.Request;
+
+ // Адрес, с которого пришёл запрос (может быть адрес прокси)
+ string publicAddress = currentRequest.ServerVariables["REMOTE_ADDR"];
+
+ // Локальный адрес компа, заполняется при перенаправлении запроса через прокси
+ string localAddress = currentRequest.ServerVariables["HTTP_X_FORWARDED_FOR"];
+
+
+ StringBuilder info = new StringBuilder();
+
+ info.AppendFormat("IP-адрес запроса: {0}.\r\nИсходный IP-адрес запроса: {1}\r\n", publicAddress, localAddress);
+
+ info.AppendFormat("Адрес web-страницы: {0}\r\n", currentRequest.Url);
+
+ return info.ToString();
+ }
+
+ ///
+ /// Обрабатывает веб запрос. Исходная точка в HttpHandler
+ ///
+ /// Контекст Http запроса
+ void IHttpHandler.ProcessRequest(HttpContext context)
+ {
+ InitLogger();
+
+ try
+ {
+ string msg = "Получен запрос на экспорт данных в формате ДГК.\r\n" + GetRequestInfo();
+
+ LogInfo(msg);
+
+ Init();
+
+ // Разбираем входные параметры
+ ParseInputParams();
+
+ // Экспортируем данные
+ ExportData();
+
+ if (context.Response.IsClientConnected)
+ LogInfo("Данные успешно отправлены.");
+ }
+ catch (ConfigurationErrorsException ex)
+ {
+ LogError(ex.Message);
+ }
+ catch (Lers.Networking.RequestTimeoutException exc)
+ {
+ LogError("Вышло время ожидания на выполнение операции.\r\n");
+ }
+ catch (Lers.Networking.ServerConnectionException exc)
+ {
+ LogError("Ошибка при попытки установить соединение с сервером ЛЭРС УЧЕТ.\r\n");
+ }
+ catch (Lers.Networking.AuthorizationFailedException exc)
+ {
+ LogError("Ошибка при попытки установить соединение с сервером ЛЭРС УЧЕТ.\r\n");
+ }
+ catch (VersionMismatchException exc)
+ {
+ LogError("Ошибка при попытки установить соединение с сервером ЛЭРС УЧЕТ.\r\n");
+ }
+ catch(Exception exc)
+ {
+ string msg = "Ошибка экспорта данных в формате ДГК. ";
+ LogError(msg);
+ throw;
+ }
+ finally
+ {
+ this.logger.LogDebug("Закрываем подключение...", CLASS_NAME);
+
+ if(server != null && server.IsConnected)
+ server.Disconnect(2000);
+
+ this.logger.Close();
+
+ context.Response.End();
+ }
+ }
+
+ #region Протоколирование
+
+ ///
+ /// Протоколирует сообщение об ошибке
+ ///
+ /// Текст сообщения
+ private void LogError(string message)
+ {
+ this.logger.LogError("Dgk:\t" + message, CLASS_NAME);
+ }
+
+ ///
+ /// Протоколирует информационное сообщение
+ ///
+ /// Текст сообщения
+ private void LogInfo(string message)
+ {
+ this.logger.LogMessage("Dgk:\t" + message, CLASS_NAME);
+ }
+
+ ///
+ /// Протоколирует отладочное сообщение
+ ///
+ /// Текст сообщения
+ private void LogDebug(string message)
+ {
+ this.logger.LogDebug("Dgk:\t" + message, CLASS_NAME);
+ }
+
+ ///
+ /// Протоколирует предупреждающее сообщение
+ ///
+ /// Текст сообщения
+ private void LogWarning(string message)
+ {
+ this.logger.LogWarning("Dgk:\t" + message, CLASS_NAME);
+ }
+
+ ///
+ /// Инициализирует логгер
+ ///
+ private void InitLogger()
+ {
+ // Считываем путь до журнала протокола
+ string logFile = System.Configuration.ConfigurationManager.AppSettings["DataAdapterFileLogPath"] ?? "";
+
+ if (logFile == "")
+ logFile = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"\LERS\Logs\Web\DataAdapter.log";
+
+ // Если каталога нет, создаем его
+ if (!Directory.Exists(Path.GetDirectoryName(logFile)))
+ Directory.CreateDirectory(Path.GetDirectoryName(logFile));
+
+ bool debug = false;
+
+ // Считываем значение включено ли протоколирование отладочных сообщений
+ string fileLogDebug = System.Configuration.ConfigurationManager.AppSettings["DataAdapterFileLogDebug"] ?? "";
+
+ if (fileLogDebug == "1")
+ debug = true;
+
+ this.logger = Logger.Create(logFile);
+
+ this.logger.LogDebugMessages = debug;
+ }
+
+ #endregion
+
+ #region Инициализация и разбор входных параметров
+
+ ///
+ /// Инициализация
+ ///
+ private void Init()
+ {
+ LogDebug("Инициализация...");
+
+ // Отключаем буферизацию
+ HttpContext.Current.Response.BufferOutput = false;
+
+ // ServerAddress
+ string serverAddress = ConfigurationManager.AppSettings["ServerAddress"] ?? "";
+
+ if (serverAddress == "")
+ serverAddress = "localhost";
+
+ // ServerPort
+ int serverPort;
+
+ if (!Int32.TryParse(ConfigurationManager.AppSettings["ServerPort"], out serverPort))
+ serverPort = 10000;
+
+ // Login
+ string login = ConfigurationManager.AppSettings["AdmLogin"];
+
+ if(string.IsNullOrEmpty(login))
+ throw new ConfigurationErrorsException("В конфигурации приложения отсутствует параметр: AdmLogin");
+
+ // Password
+ string password = ConfigurationManager.AppSettings["AdmPassword"];
+
+ if(string.IsNullOrEmpty(password))
+ throw new ConfigurationErrorsException("В конфигурации приложения отсутствует параметр: AdmPassword");
+
+ LogDebug("Инициализация завершена.");
+
+ // Соединяемся
+
+ LogDebug("Соединение с сервером ЛЭРС УЧЕТ...");
+
+ this.server = new LersServer();
+
+ this.server.VersionMismatch += server_VersionMismatch;
+
+ System.Security.SecureString securePassword = Networking.SecureStringHelper.ConvertToSecureString(password);
+
+ this.server.Connect(serverAddress, (ushort)serverPort, new Networking.BasicAuthenticationInfo(login, securePassword));
+
+ LogDebug("Соединение установлено.");
+ }
+
+ ///
+ /// Обработчик ошибки несовместимости версий сервера и фреймворка
+ ///
+ void server_VersionMismatch(object sender, VersionMismatchEventArgs e)
+ {
+#if DEBUG
+ e.Ignore = true;
+#endif
+ }
+
+ ///
+ /// Разбор входных параметров
+ ///
+ private void ParseInputParams()
+ {
+ NameValueCollection paramCollection = HttpContext.Current.Request.Params;
+
+ DateTime result;
+
+ // Начальная дата
+ if (TryParseDateParam(paramCollection, "dateFrom", out result))
+ beginDate = result;
+
+ // Конечная дата
+ if (TryParseDateParam(paramCollection, "DateTo", out result))
+ endDate = result;
+
+ // Из регламента:
+ // ДГК может в любое время выполнять запросы данных за произвольный период,
+ // но на глубину не более чем два месяца, включая отчетный.
+
+ // Комментарий Клауса:
+ // Если запрашивается большой интервал, то подрезаем его с начала,
+ // иначе получаем исключение "Слишком большой размер пакета ( > 20МБ )
+
+ // Если запрашивается интервал больше 3 месяцев, подрезаем его с начала.
+ if(((TimeSpan)endDate.Subtract(beginDate)).TotalDays > 60)
+ {
+ beginDate = endDate.Subtract(new TimeSpan(60, 0, 0, 0));
+
+ LogWarning("Интервал выборки данных превышает 60 дней. Дата начала интервала заменена на " + beginDate);
+ }
+
+ //Если интервал не корректный то устанавливаем интервал по умолчанию
+ if (beginDate > endDate)
+ {
+ beginDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
+
+ endDate = DateTime.Now;
+
+ LogWarning("Конечная дата периода превышает начальную. Параметры были установлены по умолчанию.");
+ }
+
+ // Тип данных
+ if (!Int32.TryParse(paramCollection["PeriodType"], out dataPeriodType))
+ dataPeriodType = -1; // Суточные и часовые
+
+ // По умолчанию выдаем и суточные и часовые данные
+ if (dataPeriodType != -1 && dataPeriodType != 0 && dataPeriodType != 1)
+ dataPeriodType = -1;
+
+ LogDebug(String.Format("параметры запроса: beginDate = {0}, endDate = {1}, dataPeriodType = {2}",
+ beginDate, endDate, dataPeriodType));
+ }
+
+ ///
+ /// Пытается разобрать параметр дата задающую начало и конец периода
+ ///
+ /// Коллекция параметров, полученная из HttpContext.Request.Params
+ /// Имя параметра для разбора
+ /// Дата полученная из указанного параметра
+ /// Результат разбора: true - успех, false - провал.
+ private bool TryParseDateParam(NameValueCollection paramCollection, string paramName, out DateTime result)
+ {
+ result = new DateTime();
+
+ // Проверяем есть ли вообще параметры, есть ли необходимый нам параметр, не пустой ли он
+ if (paramCollection.Count > 0 &&
+ !String.IsNullOrEmpty(paramCollection[paramName]))
+ {
+ if (DateTime.TryParseExact(paramCollection[paramName], "yyyyMMddHHmm", null, System.Globalization.DateTimeStyles.AssumeLocal, out result))
+ return true;
+
+ if (DateTime.TryParseExact(paramCollection[paramName], "yyyyMMdd", null, System.Globalization.DateTimeStyles.AssumeLocal, out result))
+ return true;
+ }
+
+ return false;
+ }
+
+ #endregion
+
+ #region Выдача данных
+
+ ///
+ /// Экспортирует данные потребления указанного типа
+ ///
+ /// Точка учета
+ /// Тип данных: true - суточные, false - часовые
+ private void ExportConsumption(MeasurePoint measurePoint, bool isDay)
+ {
+ // TODO: Сократить количество запросов на сервер, одновременно запрашивая суточные и часовые данные
+
+ // Получаем данные потребления по точке учета
+ MeasurePointConsumptionRecordCollection consumption = measurePoint.Data.GetConsumption(beginDate, endDate, ((isDay) ? DeviceDataType.Day : DeviceDataType.Hour));
+
+ // Измеряемый ресурс
+ int systemTypeId = (int)measurePoint.SystemType;
+
+ // Номер точки учета
+ int number = measurePoint.Number ?? 0;
+
+ string output = "";
+
+ foreach (MeasurePointConsumptionRecordWater dataRecord in consumption)
+ {
+ if (dataRecord.M_in == null)
+ continue;
+
+ // Накапливаем данные в строке
+ output = number + ";"
+ + ((isDay) ? dataRecord.DateTime.ToString("yyyy-MM-dd") : dataRecord.DateTime.ToString("yyyy-MM-dd HH:mm"))
+ + ";2;"
+ + systemTypeId + ";"
+ + (dataRecord.T_in ?? 0) + ";"
+ + (dataRecord.T_out == null ? "" : dataRecord.T_out.ToString()) + ";"
+ + (dataRecord.M_in ?? 0) + ";"
+ + (dataRecord.M_out == null ? "" : dataRecord.M_out.ToString()) + ";"
+ + (dataRecord.Q_in == null? "" : dataRecord.Q_in.ToString()) + ";"
+ + (dataRecord.Q_out == null ? "" : dataRecord.Q_out.ToString()) + ";"
+ + (dataRecord.P_in == null ? "" : dataRecord.P_in.ToString()) + ";"
+ + (dataRecord.P_out == null ? "" : dataRecord.P_out.ToString()) + ";"
+ + (dataRecord.WorkTime == null ? "" : dataRecord.WorkTime.ToString()) + ";"
+ + Convert.ToInt32(isDay) + ";\n";
+
+ // Выдаем браузеру
+ HttpContext.Current.Response.Write(output);
+ }
+ }
+
+ ///
+ /// Отправляет заголовок
+ ///
+ private void SendHeader()
+ {
+ HttpResponse response = HttpContext.Current.Response;
+
+ // Определяем имя файла
+ string fileName = "" + ((beginDate != DateTime.MinValue) ? beginDate.ToString("yyyyMMddHHmm") : "")
+ + "-" + ((endDate != DateTime.MinValue) ? endDate.ToString("yyyyMMddHHmm") : "")
+ + ((dataPeriodType > -1) ? "_" + dataPeriodType : "")
+ + ".csv";
+
+ // Подготавливаем заголовок
+ // Ставим в качестве ответа, файл в кодировке по умолчанию
+ response.ContentEncoding = System.Text.Encoding.Default;
+ response.ContentType = "application/x-download";
+ response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(fileName));
+
+ // Выдаем браузеру заголовок данных потребления
+ response.Write("MeasurePointID;DataDate;DataSource;ResourceTypeID;T_in;T_out;M_in;M_out;H_in;H_out;P_in;P_out;WorkTime;IsDay\n");
+ }
+
+ ///
+ /// Экспортирует данные потребления
+ ///
+ private void ExportData()
+ {
+ LogDebug("Отправка данных для администрации г. Хабаровска в ответ на запрос...");
+
+ SendHeader();
+
+ MeasurePoint[] measurePoints = this.server.MeasurePoints.GetList(MeasurePointType.Regular);
+
+ // Выдаем все суточные данные потребления
+ if (dataPeriodType == 0 || dataPeriodType == -1)
+ {
+ foreach (MeasurePoint measurepoint in measurePoints)
+ {
+ // Выгружаем данные только по воде
+ if (measurepoint.SystemType != SystemType.ColdWater && measurepoint.SystemType != SystemType.HotWater && measurepoint.SystemType != SystemType.Heat)
+ continue;
+
+ ExportConsumption(measurepoint, true);
+
+ if (!HttpContext.Current.Response.IsClientConnected)
+ {
+ LogDebug("Клиент был отключен от веб-сервера.");
+ return;
+ }
+ }
+ }
+
+ // Выдаем все часовые данные потребления
+ if (dataPeriodType == 1 || dataPeriodType == -1)
+ {
+ foreach (MeasurePoint measurepoint in measurePoints)
+ {
+ // Выгружаем данные только по воде
+ if (measurepoint.SystemType != SystemType.ColdWater && measurepoint.SystemType != SystemType.HotWater && measurepoint.SystemType != SystemType.Heat)
+ continue;
+
+ ExportConsumption(measurepoint, false);
+
+ if (!HttpContext.Current.Response.IsClientConnected)
+ {
+ LogDebug("Клиент был отключен от веб-сервера.");
+ return;
+ }
+ }
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/KhvAdmDataAdapter/App_Code/Logger.cs b/KhvAdmDataAdapter/App_Code/Logger.cs
new file mode 100644
index 0000000..5d1e206
--- /dev/null
+++ b/KhvAdmDataAdapter/App_Code/Logger.cs
@@ -0,0 +1,267 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Threading;
+
+namespace Lers.Utils
+{
+ ///
+ /// Протоколирует сообщения в файл.
+ ///
+ public class Logger : IDisposable
+ {
+ ///
+ /// Тип сообщения в журнале.
+ ///
+ private enum LogType
+ {
+ ///
+ /// Отладочное сообщение.
+ ///
+ Debug = 0,
+
+ ///
+ /// Информационное сообщение.
+ ///
+ Info = 1,
+
+ ///
+ /// Предупреждение.
+ ///
+ Warning = 2,
+
+ ///
+ /// Ошибка.
+ ///
+ Error = 3,
+ }
+
+ private Stream stream;
+
+ private StreamWriter streamWriter;
+
+ ///
+ /// Определяет, нужно ли протоколировать отладочные сообщения.
+ ///
+ public bool LogDebugMessages { get; set; }
+
+ ///
+ /// Определяет, нужно ли протоколировать идентификатор потока
+ ///
+ public bool LogThreadId { get; set; }
+
+ ///
+ /// Инициализирует новый экземпляр класса.
+ ///
+ /// Поток записи.
+ private Logger(Stream stream)
+ {
+ if (stream == null)
+ throw new ArgumentNullException("stream");
+
+ this.stream = stream;
+ this.streamWriter = new StreamWriter(stream, Encoding.UTF8);
+
+ WritePreamble();
+ }
+
+ ///
+ /// Создает новый экземпляр, протоколирующий сообщения в указанный файл.
+ ///
+ /// Имя файла журнала.
+ /// Возвращает экземпляр .
+ public static Logger Create(string fileName)
+ {
+ // Если папка не существует, то создаем её.
+
+ string logDirectory = Path.GetDirectoryName(fileName);
+
+ if (!Directory.Exists(logDirectory))
+ {
+ Directory.CreateDirectory(logDirectory);
+ }
+
+ // Открываем файловый поток на запись. Если файл уже существует, то будем дописывать в него,
+ // если нет - создаем новый файл.
+
+ FileMode fileMode;
+
+ if (File.Exists(fileName))
+ fileMode = FileMode.Append;
+ else
+ fileMode = FileMode.CreateNew;
+
+ FileStream stream = new FileStream(fileName, fileMode, FileAccess.Write, FileShare.Read);
+
+ // Создаем новый экземпляр класса и возвращаем его.
+
+ try
+ {
+ return new Logger(stream);
+ }
+ catch
+ {
+ // При ошибке закрываем файловый поток.
+
+ stream.Close();
+
+ throw;
+ }
+ }
+
+ ///
+ /// Закрывает файл журнала.
+ ///
+ public void Close()
+ {
+ Dispose();
+ }
+
+ ///
+ /// Протоколирует информационное сообщение.
+ ///
+ /// Текст сообщения.
+ /// Источник сообщения.
+ public void LogMessage(string message, string source)
+ {
+ Log(LogType.Info, message, source);
+ }
+
+ ///
+ /// Протоколирует предупреждающее сообщение.
+ ///
+ /// Текст сообщения.
+ /// Источник сообщения.
+ public void LogWarning(string message, string source)
+ {
+ Log(LogType.Warning, message, source);
+
+ }
+
+ ///
+ /// Протоколирует сообщение об ошибке.
+ ///
+ /// Текст сообщения.
+ /// Источник сообщения.
+ public void LogError(string message, string source)
+ {
+ Log(LogType.Error, message, source);
+ }
+
+ ///
+ /// Протоколирует отладочное.
+ ///
+ /// Текст сообщения.
+ /// Источник сообщения.
+ public void LogDebug(string message, string source)
+ {
+ // Отладочные сообщения протоколируем только если включено.
+
+ if (this.LogDebugMessages)
+ Log(LogType.Debug, message, source);
+ }
+
+ ///
+ /// Протоколирует сообщение в журнал.
+ ///
+ /// Важность сообщения.
+ /// Текст сообщения.
+ /// Источник сообщения.
+ private void Log(LogType logType, string message, string source)
+ {
+ CheckDisposed();
+
+ if (message == null)
+ throw new ArgumentNullException("message");
+
+ if (source == null)
+ throw new ArgumentNullException("source");
+
+ // Сонхронизируем доступ из разных потоков.
+
+ lock (this.streamWriter)
+ {
+ // Записываем строку и очищаем буфер, чтобы строка сразу появилась в лог-файле.
+
+ if(this.LogThreadId)
+ this.streamWriter.WriteLine("{0:dd-MM-yyyy HH:mm:ss.fff}\t{1}:{2:000}\t{3}\t\t\t{4}",
+ DateTime.Now, FormatLogType(logType), Thread.CurrentThread.ManagedThreadId, message, source);
+ else
+ this.streamWriter.WriteLine("{0:dd-MM-yyyy HH:mm:ss.fff}\t{1}\t{2}\t\t\t{3}", DateTime.Now, FormatLogType(logType), message, source);
+
+ this.streamWriter.Flush();
+ }
+
+ // В отладочной версии дополнительно протоколируем в окно Output отладчика.
+
+#if DEBUG
+ System.Diagnostics.Debugger.Log((int)logType, source, message + "\r\n");
+#endif
+ }
+
+ ///
+ /// Записывает заголовок в файл журнала.
+ ///
+ private void WritePreamble()
+ {
+ this.streamWriter.WriteLine("========================================");
+ this.streamWriter.WriteLine("== Журнал открыт " + DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss.fff"));
+ this.streamWriter.WriteLine("========================================");
+
+ this.streamWriter.Flush();
+ }
+
+ private static string FormatLogType(LogType logType)
+ {
+ switch (logType)
+ {
+ case LogType.Debug:
+ return "D";
+
+ case LogType.Info:
+ return "I";
+
+ case LogType.Warning:
+ return "W";
+
+ case LogType.Error:
+ return "E";
+
+ default:
+ throw new ArgumentOutOfRangeException("logType");
+ }
+ }
+
+ #region IDisposable
+
+ private bool isDisposed = false;
+
+ ///
+ /// Проверяет, что экземпляр не уничтожен.
+ ///
+ private void CheckDisposed()
+ {
+ if (this.isDisposed)
+ throw new ObjectDisposedException("Использование экземпляра невозможно, т.к. объект был закрыт.");
+ }
+
+ ///
+ /// Освобождает ресурсы.
+ ///
+ public void Dispose()
+ {
+ if (!this.isDisposed)
+ {
+ this.streamWriter.Close();
+ this.stream.Close();
+
+ this.streamWriter = null;
+ this.stream = null;
+
+ this.isDisposed = true;
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/KhvAdmDataAdapter/KhvAdmDataAdapter.csproj b/KhvAdmDataAdapter/KhvAdmDataAdapter.csproj
new file mode 100644
index 0000000..5688900
--- /dev/null
+++ b/KhvAdmDataAdapter/KhvAdmDataAdapter.csproj
@@ -0,0 +1,85 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {0C6B7048-E464-439D-82CD-99532A932E5A}
+ {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
+ Library
+ Properties
+ Lers.Web.DataAdapter.KhvAdm
+ Lers.KhvAdmDataAdapter
+ v4.0
+
+
+ 3.5
+
+
+ false
+
+
+ true
+ full
+ false
+ bin\
+ DEBUG;TRACE
+ prompt
+ 4
+ Off
+
+
+ pdbonly
+ true
+ bin\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\..\Lers.System\bin\x86\Debug\Lers.System.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ False
+ 89
+ /
+
+
+ False
+ False
+
+
+ False
+
+
+
+
+
\ No newline at end of file
diff --git a/KhvAdmDataAdapter/KhvAdmDataAdapter.sln b/KhvAdmDataAdapter/KhvAdmDataAdapter.sln
new file mode 100644
index 0000000..44e3380
--- /dev/null
+++ b/KhvAdmDataAdapter/KhvAdmDataAdapter.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KhvAdmDataAdapter", "KhvAdmDataAdapter.csproj", "{0C6B7048-E464-439D-82CD-99532A932E5A}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0C6B7048-E464-439D-82CD-99532A932E5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0C6B7048-E464-439D-82CD-99532A932E5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0C6B7048-E464-439D-82CD-99532A932E5A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0C6B7048-E464-439D-82CD-99532A932E5A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0C6B7048-E464-439D-82CD-99532A932E5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0C6B7048-E464-439D-82CD-99532A932E5A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0C6B7048-E464-439D-82CD-99532A932E5A}.Release|x64.ActiveCfg = Release|Any CPU
+ {0C6B7048-E464-439D-82CD-99532A932E5A}.Release|x86.ActiveCfg = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/KhvAdmDataAdapter/Properties/AssemblyInfo.cs b/KhvAdmDataAdapter/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..9b874e4
--- /dev/null
+++ b/KhvAdmDataAdapter/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Управление общими сведениями о сборке осуществляется с помощью
+// набора атрибутов. Измените значения этих атрибутов, чтобы изменить сведения,
+// связанные со сборкой.
+[assembly: AssemblyTitle("ЛЭРС УЧЕТ. Адаптер данных для администрации г. Хабаровска")]
+[assembly: AssemblyDescription("Выполняет преобразование данных в формат экспорта администрации г. Хабаровска")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("ООО \"Хабаровский центр энергоресурсосбережения\"")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyProduct("Система диспетчеризации ЛЭРС УЧЕТ")]
+[assembly: AssemblyCopyright("© 2000-2011, Хабаровский центр энергоресурсосбережения")]
+[assembly: AssemblyTrademark("Внимание: Данная компьютерная программа защищена законами об авторских правах и международными соглашениями. Незаконное воспроизведение или распространения данной программы или любой ее части влечет гражданскую и уголовную ответственность.")]
+
+// Параметр ComVisible со значением FALSE делает типы в сборке невидимыми
+// для COM-компонентов. Если требуется обратиться к типу в этой сборке через
+// COM, задайте атрибуту ComVisible значение TRUE для этого типа.
+[assembly: ComVisible(false)]
+
+// Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM
+[assembly: Guid("a0027496-d7ea-4530-9e78-3033f1d4e2c7")]
+
+// Сведения о версии сборки состоят из следующих четырех значений:
+//
+// Основной номер версии
+// Дополнительный номер версии
+// Номер построения
+// Редакция
+//
+// Можно задать все значения или принять номер построения и номер редакции по умолчанию,
+// используя "*", как показано ниже:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/KhvAdmDataAdapter/web.config b/KhvAdmDataAdapter/web.config
new file mode 100644
index 0000000..09dd29b
--- /dev/null
+++ b/KhvAdmDataAdapter/web.config
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index e4a247d..824641c 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,9 @@
# samples
Примеры использования Lers Framework
+
+Проекты:
+
+AttributesSample Работа с атрибутами. Консольное приложение.
+GetDataSample Получение данных из ЛЭРС УЧЁТ. Консольное приложение.
+ImportTemperature Импорт температуры наружного воздуха в ЛЭРС УЧЁТ.
+KhvAdmDataAdapter Экспорт данных из ЛЭРС УЧЁТ. Обработчик HttpHandler для веб-сайта