Создание проекта "Умный Дом"

georgiev-ruslan
Offline
Зарегистрирован: 31.10.2016

Здравствуйте уважаемые форумчане: люди добрые! Недавно загорелся идеей создания своего "умного дома" на arduino под конкретный проект, прилагаемый на изображениях ниже. Немного о данном проекте:
1) Цокольный этаж: Бильярдная, Спортзал, Сауна, Сан/узел, Холл, Серверная;
2) Первый этаж: Кухня, Гостинная, Тамбур, Сан/узел, Холл, Кабинет, Гараж;
3) Второй этаж: Детская, Гостинная, Сан/узел, Холл, Спальня, Спальня
4) Кровля и чердак: одно общее помещение;
5) Двор и периметр: Планируется также управление освещением и различными датчиками на улице.
Цокольный этаж
Первый этажВторой этаж

Предположительно вырисовывается сама идея "умного дома":
1) Компьютер на операционной системе Windows 10.
2) На компьютере установлено приложение UI, через которое будет происходить управление "умным домом".
3) Приложение отсылает команды через COM порт (Serial) управляющему устройству (Например, Arduino 2560) /Master/
4. Arduino 2560 управляет всеми другими контролерами (Например, Arduino Uno). /Slave/
5. Контролеры на базе Arduino Nano в свою очередь управляют различными реле, снимают показания с датчиков и тд. Вообщем выполняют функции, на них возложенные.

И вот как это всё реализовать, не знаю. В интернете очень много примеров под различные задачи (пункт 5). А как это всё вместе связывается, хз. Читая различную информацию на форумах, предположительно понимаю, что все платы необходимо связать между собой по RS 485 с помощью RS max485, предворительно присвоив каждой плате Arduino свой ID номер в сети. Погуглив, наткнулся на хороший урок на данную тему в youtube: https://www.youtube.com/watch?time_continue=89&v=CDn2mM9vSUk (в видео указана только 2 часть, но изучил все три части). К сожалению там не показывается схема подключения, где куда и какие пины подключать, используя данный скетч. Собственно отсюда вытекают несколько вопросов:
1) Как реализовать такую схему подключения и организовать сеть из плат Arduino, согласно иерархии и расположения помещений в доме? В моём понимании есть Приложение, которое через Serial порт управляет главным контроллером / Master / . Главный контроллер в свою очередь принимает команды от приложения и распределяет их контролерам, которые отвечают за каждый этаж / Slave / . Контроллеры, отвечающие за этажи, посылают (дублируют команды от Master`а контроллерам низшего уровня Arduino Nano. (Как их обозвать - не знаю, им ведь тоже нужны ID?). Ну и каждая Arduino Nano отвечает за одно помещение, к которой подключены различные датчики, реле, приводы и тд. (Например, Кухня, Гараж, Спальня и тд.
2) К сожалению не сильно силён в програмировании, хотя и работаю в IT сфере. Если бы всё соединялось по TCP\IP через хаб, вопросов бы не возникало. Присвоил бы каждой плате некий IP адрес и тд. Но здесь, к сожалению, не могу понять, каким образом должны общаться и взаимодействовать Arduino между собой? К каким пинам подключать, какой скетч должен быть написан на Master`е, какие на Slave, какие на контроллерах, отвечающие за помещение? (приём <=> обмен).
3) На данном этапе изучения Arduino я очень хочу понять, как каждая плата взаимодействует между собой по rs485 (три и более плат). Можно ли из них зделать такую иерархию, и если да, то каким образом это делается? А если нет, то как соединить эти платы между собой таким образом, чтобы сделать приблезительно похожую концепцию "умного дома"? Заранее всем откликнувшимся спасибо за помощь и за настовление на путь истинный! :)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

georgiev-ruslan пишет:

Присвоил бы каждой плате некий IP адрес и тд. 

Кто-то или что-то мешает? Если Вы умеете соединять так, то соединяйте так.

bankir_1986
Offline
Зарегистрирован: 23.03.2015

я стесняюсь спросить (я считаю себя новичком в этом, НО):

1. На кой тебе UNO как промежуточное звено? И самое главное чем оно отличается UNO от nano  или mini в части МК?

2. Если управление от ПК - нафига Mega?

3. Начинай на форуме с поиска "Умный дом" - варианов полно.

4. Продавцы-консультанты по продаже ПК тоже считают себя работникамив IT сфере. Вы конкретно к какой группе относитесь?

Алексей Н
Offline
Зарегистрирован: 02.01.2016

Очень широкая тема. И способов может быть множество. И, например, одна Мега с ее полсотнью пинов может обойтись без дополнитеьлных УНО, НАНО.

Ардуино между собой можно соединить несколькими способами. Как проводных, так и беспроводных.

Я бы посоветовал чуть больше проработать проект. Сейчас Вы перескочили через одну ступеньку. Что именно Вы хотите получить от умного дома? Управление светом, спускание воды в унитазе, контроль за отоплением, и т.д. Составьте список того, что Вы хотите получить в конечном итоге. И в зависимости от этого можно будет что то советовать.

Судя по рисункам дома у Вас нет :) Потому что нет лестницы на третий этаж. А те лестницы, которые есть, упираются в стены.

arduino328
Offline
Зарегистрирован: 01.09.2016
georgiev-ruslan
Offline
Зарегистрирован: 31.10.2016

ЕвгенийП: Я так понимаю, что вместо IP адресов в Arduino можно указать некий ID устройства, к которому будет обращаться главный контроллер в сети (например Arduino 2560)? Чтобы присвоить каждой Arduino IP адрес, необходим Ethernet shild, который в свою очередь приводит весь проект к удорожанию. (поправте меня, если я не правильно мыслю в этом направлении, пожалуйста). Поэтому связать все платы Arduino планируется через RS 485.

bankir_1986: Отвечу на ваши вопросы по порядку:
1) "Промежуточное звено (например, Arduino Uno)" в моём понимании, служит лишь для наибольшего колличества "подключаемых устройств" на этаже (например, Arduino Nano). А Arduino Nano является уже конечным МК, который управляет реле, сервоприводами, к которому подключены датчики.
2) Если управление происходит от ПК, то Arduino Mega служит "промежуточным звеном" для того, чтобы получать команды от ПК и передавать их непосредственно "по адресу" микроконтроллеру, который в свою очередь должен выполнить какое либо действие. Например: Нужно включить удалённо свет. Сценарий такой: Запускаем приложение на ПК. Отправляем команду Arduino Mega по Serial о том, что необходимо включить свет. Arduino Mega же дублирует эту команду на МК низшего уровня. (В идеале сразу же на Arduino Nano, но мне кажется на Mega просто ни хватит портов для 24 помещений, в которых необходимо управлять не только светом, но и различными датчиками температуры, движения и тд и тп.). Микроконтроллер, который находится в комнате, получает команду о том, что нужно включить свет, и включает реле, зажигающее люстру. Также к микроконтроллеру, который находится в комнате, можно подключить датчики температуры, влажности, дыма и тд.
3) Спасибо большое, так и сделаю! :)
4) Я работаю в больнице, мастер по ремонту медицинского оборудования и компьютерной техники. С программированием микроконтроллеров ни когда не сталкивался, но тема очень интересна. Её и хотел бы применить в данном случае.

Алексей Н: Эта тема действительно очень широкая и обширная, и на данном этапе меня интересует именно связь между несколькими Arduino платами, для того, чтобы потом каждой из этих плат можно было управлять с компьютера.
В интернете читал про способы связи между двумя платами Arduino через шину I2C, но RS485 предпочтительнее изза дальности действия на длинные дистанции. Впринципе, если связать две платы - там всё ясно. Но, как это сделать с тремя и более плат? Предпологается, что в каждой комнате дома будет свой микроконтроллер, который будет отвечать за задачи, на него возложенные в комнате. Таких комнат будет 24.
ps: Лестницы на третий этаж (чердак) в помещении не предусмотренно, и выход будет с улицы. Пока это всего лишь проект, к которому и хочется привязать "Умный Дом на Arduino".

arduino328: Благодарю Вас. Для меня обязательно к прочтению! Буду изучать! :)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

georgiev-ruslan пишет:

ЕвгенийП: Я так понимаю, что вместо IP адресов в Arduino можно указать некий ID устройства,

да, нет. Просто ставьте на Ардуино совсем недорогой wi-fi модуль (например, ESP-01) и он вполне получит адрес по DHCP или сами назначите. Если у Вас пачка таких ардуин, то они все будут иметь уникальные адреса, если у Вас DHCP нормально настроено (или если Вы сами правильно всё назначили).

Алексей Н
Offline
Зарегистрирован: 02.01.2016

ЕвгенийП пишет:
да, нет. Просто ставьте на Ардуино совсем недорогой wi-fi модуль (например, ESP-01) и он вполне получит адрес по DHCP или сами назначите.

Можно опять же продумать более подробно желаемые плюшки и возможно обойтись одним ЕСП без ардуино. Со всеми плюсами и минусами WiFi. Если планируется 24 контроллера только на комнаты, возможно это вариант. Опять же вопрос. А все 24 микроконтроллера должны быть связаны и друг с другом? Или все-таки один центральный "мастер" и множество "слейвов"?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Да, не Алексей, ТС в первом посте сказал, что мол вязать IP сеть умеет а другое чего - так не очень. Ну я и посоветовал ему делать как умеет. Знакомая дорога всегда короче и безопасней.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

georgiev-ruslan, во-первых, Вы совершенно правы - проектировать дом умным следует на стадии общего проектирования. Делать "умным" уже построенное здание - задача неблагодарная.

С другой стороны настораживает, что Вы решили взяться за эту задачу, не имея опыта в главном - в программировании. Тут даже и не знаю, что посоветовать: без такого опыта Вы не сумеете спроектировать систему. В принципе, учиться можно на практике в процессе осуществления какого-нибудь проекта. Но, боюсь, умный дом в качестве этого первого проекта категорически не подходит. В процессе приобретения опыта Вам неизбежно придется устранять ошибки проектирования и неоднократно переделывать проект, в том числе и начиная с нуля - с перепроектирования. Когда проект является обособленным - это не всегда безболезненно, но осуществимо. Если же проект привязан к дому... ну не будетие же Вы ломать дом до основания, когда выявятся ошибки в проекте. И мне сомнительно, что даже будете вскрывать уже оштукатуренные стены, чтобы допроложить необходимую, но не предусмотренную проводку. По сути дела Вы лишаетесь того огромного преимущества, о котором я писал в первом абзаце - возможности строить с самого начала умный дом, а не встраивать элементы умного дома в уже построенное здание.

Я бы все-таки попытался, пока разрабатывается проект дома, параллельно этому взяться за какой проект поскромнее - ну, например, за домашнюю метеостанцию. Кстати, может, она даже войдет в окончательный проект умного дома в качестве составной части. Ну и поймете, как работать с датчиками вообще и с датчиками температуры/влажности в частности.

Начинать проект умного дома, как Вам уже написали, нужно с составления списка хотелок. Т.е. с описания того, что этот дом должен уметь. Потом разрабатывается общий алгоритм, включающий основное распределение обязанностей между отдельными контроллерами. Судя по тому, что Вы планируете по одному контроллеру на каждое помещение, Вы об этом даже не начинали думать. Иначе контроллеры бы у Вас оказались привязанными к функциям, а не к помещениям.

По поводу TCP/IP: раз у Вас есть опыт, именно по этому пути и нужно идти. Для связи 2-3 Ардуин вполне рационально пользоваться более или менее специализированными именно для Ардуин решениями. Но если речь идет о сети из порядка 10 устройств, TCP/IP становится достаточно удачным выбором вследствие легкой масштабируемости.

Ну и мелочи по оборудованию:

1. Я был удивлен упоминанием о дороговизне Ethernet shild. На мой взгляд, это в любом случае исчезающе мало по сравнению с ценой умного дома.

2. Arduino Uno и Arduino Nano - это одно и то же, отличаются только размером платы. В принципе, Uno удобно только в двух случаях - при макетировании (и то неочевидно) и если используется стандартный Shield, выполненный в типоразмере Uno. Во всех остальных случаях удобнее Nano. Кроме тех случаев, когда еще удобнее Pro Mini, которая практически то же, что и Nano, но без интерфейса USB.

axill
Offline
Зарегистрирован: 05.09.2011

ваш подход вполне реализуем, но не лишен целой кучи изъянов

- придется очеееень много писать своего, те изобретать велосипед сидя в велосипедном магазине

- решение на базе вин10 слишком сложное, чтобы быть надежным и чтобы требовало минимум ухода

я бы на вашем месте посмотрел в второну такого, максимальное на базе готовых примеров используя copy-paste

- центральный сервер на базе мини писи типа raspberry или orange или еше кого, те, что без жестких дисков, на юниксе или андроиде и готовы без обновления и возни работать годами без перезагрузки

- туда установить mqtt broker для организации шини общения всех устройств умного дома

- в качестве консоли упралвние установить один из open source проектов, консоль управления позволяет управлять удаленно, через смартфоны и позволяет настраивать всякую более сложную логику. Например openhab который можно установить на тот же миниписи, что и mqtt

- а дальше полет фантазии по конечным устройствам. Конечные устройства это сенсоры и содули управления нагрузкой. Их можно делать на:

- esp8266 это мини система за 100р платка со встроенным wifi, програмировать можно на Си используя SDK, на диалекте Си++ в среде Ардуино или в скрипитовом языке на прошивке NodeMCU

- на ардуино использую для передачи провода (ethernet или RS485) или радио (-NRF024 или всякие 433МГц). Копи пастить можно например с mysensors.org

- можно частично использовать покупное, например радиорозетки и выключатели которыми можно управдять через библиотеку RSwitch

 

georgiev-ruslan
Offline
Зарегистрирован: 31.10.2016

Итак, дело немного сдвинулось с места, и было решено учиться всему на практике. Сейчас на данный момент предпочтительно все устройства arduino завязать в единую локальную сеть. Чтобы у каждой платы был свой ip адрес, используя ethernet shild. (по совету ЕвгенийП и andriano).
На данном этапе самостоятельно пишу универсальное WPF приложение. На скрине прилагаю то, что собственно получилось. В приложении можно выбрать раздел (этаж, периметр и тд..).. а также выбрать страницу комнаты, в которой располагаются выключатели и датчики.

Задача следующая: приложение посылает сообщение на плату arduino примерно такого содержания: [ip адрес платы|код команды] "192.168.0.1 01". Arduino, которой пренадлежит этот адрес выполняет команду.
На данный момент столкнулся со следующей проблемой: каким образом в wpf с# необходимо отправлять команды в обработчике переключателя "toggle" в serial port. Пересмотрел множество примеров, но там под windows form... Схожий пример указан в коде. (9 и 14 строка, ошибка) Я так полагаю что в моём приложении нет нужной библиотеки? Как обойтись без неё?

 private async void toggleSwitch001Light_Toggled(object sender, RoutedEventArgs e)
        {
            ToggleSwitch toggleSwitch = sender as ToggleSwitch; // объявляем переменную toggleSwitch
            if (toggleSwitch != null) // если нажат переключатель ToggleSwitch
            {
                if (toggleSwitch.IsOn == true) // если выключатель во включённом положении, то
                {
                    string cmd = "192.168.10.1 1"; // посылаемое сообщение в сериал
                 <strong>   var res = await App.BluetoothManager.SendMessageAsync(cmd); // послать переменную cmd</strong>
                }
                else // если в выключенном положении
                {
                    string cmd = "192.168.10.1 0"; // посылаемое сообщение в сериал
                   <strong> var res = await App.BluetoothManager.SendMessageAsync(cmd); // послать переменную cmd</strong>
                }
            }
        }

 

georgiev-ruslan
Offline
Зарегистрирован: 31.10.2016

Всем доброго времени суток! Спустя некоторое время я всё таки нашёл способ управлять Arduino через UWP приложение. Скачал книгу про связь между Arduino и UWP приложения для Windows 10. Там есть уроки по связи ардуинки через ethernet shild, bluetooth и wifi соединение. Уже внедрил данный код в своё приложение. Ошибок не обнаружил. Если кому нибудь интересна книга, скидываю в этом сообщении. Вдруг пригодиться. :) Kurniawan A. - Arduino Programming with .NET and Sketch https://yadi.sk/i/L5Imqvmr3RoJd5https://yadi.sk/i/L5Imqvmr3RoJd5

На данный момент логика простая: UWP приложение отправляет GET запрос на web server Arduino, и выводит результат через http, но не на странице в браузере, а в приложении windows 10.

Скетч на Arduino:

#include <SPI.h>
#include <Ethernet.h>

int led1 = 5; 
int led2 = 4;
int led3 = 3;

int ledPin = 5;  // инициализируем пин для светодиода
int inputPin = 2;  // инициализируем пин для получения сигнала от пироэлектрического датчика движения
int pirState = LOW;  // начинаем работу программы, предполагая, что движения нет
int val = 0;  // переменная для чтения состояния пина

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 1, 178);
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);

void setup() {
pinMode(ledPin, OUTPUT);  // объявляем светодиод в качестве  OUTPUT
pinMode(inputPin, INPUT);  // объявляем датчик в качестве INPUT
  
// Open serial communications and wait for port to open:
Serial.begin(9600);
delay(10);

// prepare GPIO5
pinMode(led1, OUTPUT); 
pinMode(led2, OUTPUT); 
pinMode(led3, OUTPUT); 
digitalWrite(led1, 0); 
digitalWrite(led2, 0); 
digitalWrite(led3, 0); 

// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
}

void loop() {
  val = digitalRead(inputPin);  // считываем значение с датчика
if (val == HIGH) {  // проверяем, соответствует ли считанное значение HIGH
digitalWrite(ledPin, HIGH);  // включаем светодиод
if (pirState == LOW) {
// мы только что включили
Serial.println("Motion detected!");
// мы выводим на серийный монитор изменение, а не состояние
pirState = HIGH;
}
} else {
digitalWrite(ledPin, LOW); // выключаем светодиод
if (pirState == HIGH){
// мы только что его выключили
Serial.println("Motion ended!");
// мы выводим на серийный монитор изменение, а не состояние
pirState = LOW;
}
// Check if a client has connected 
EthernetClient client = server.available(); 
if (!client) { 
  return;
}
// Wait until the client sends some data 
Serial.println("new client"); 
while(!client.available()){ 
  delay(1);
}

// Read the first line of the request 
String req = client.readStringUntil('\r');
Serial.println(req); 
client.flush(); 

// Match the request 
int val1 = 0; 
int val2 = 0; 
int val3 = 0; 
int ledreq = 0;
if (req.indexOf("/gpio1/0") != -1) { 
  val1 = 0; 
  ledreq = 1;
}
else if (req.indexOf("/gpio1/1") != -1) { 
  val1 = 1; 
  ledreq = 1;
}
else if (req.indexOf("/gpio2/0") != -1) { 
  val2 = 0; 
  ledreq = 2;
}
else if (req.indexOf("/gpio2/1") != -1) { 
  val2 = 1; 
  ledreq = 2;
}
else if (req.indexOf("/gpio3/0") != -1) { 
  val3 = 0; 
  ledreq = 3;
}
else if (req.indexOf("/gpio3/1") != -1) { 
  val3 = 1; 
  ledreq = 3;
}
else {
Serial.println("invalid request");
client.stop();
return;
}

// Set GPIO2 according to the request 
if(ledreq==1)
digitalWrite(led1, val1); 
if(ledreq==2)
digitalWrite(led2, val2); 
if(ledreq==3) 
digitalWrite(led3, val3);

client.flush();

// Prepare the response
String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n"; 

if(ledreq==1) { 
  s += "LED1 is "; 
  s += (val1)? "ON": "OFF";
}else if(ledreq==3) { 
  s += "LED3 is "; 
  s += (val3)? "ON": "OFF";
}
s += "</html>\n";

// Send the response to the client
client.print(s);
delay(1);
client.stop();
Serial.println("Client disonnected");
}
}

Код страницы: Page001.cs на С#

namespace Smart_Home_Edition
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class Page001 : Page
    {
        public Page001()
        {
            this.InitializeComponent();
        }

        // Переключатель
        private void toggleLed1_Toggled(object sender, RoutedEventArgs e)
        {
            string svr = txtIP.Text;
            string url = string.Format("http://{0}/gpio1/0", svr); int state = 0;
            if (toggleLed1.IsOn)
            {
                url = string.Format("http://{0}/gpio1/1", svr); state = 1;
            }
            SendCommand(url);
            UpdateStatus(1, state);
        }
        // Обновление статуса в текстовом поле
        private void UpdateStatus(int led, int state)
        {
            if (state == 1)
                txtStatus.Text = string.Format("LED {0} is ON", led);
            else
                txtStatus.Text = string.Format("LED {0} is OFF", led);
        }
        // Отправка команд и Get запросов
        private async void SendCommand(string url)
        {
            HttpClient httpClient = new HttpClient(); var headers = httpClient.DefaultRequestHeaders;
            Uri requestUri = new Uri(url);
            HttpResponseMessage httpResponse = new HttpResponseMessage(); try
            {
                //Send the GET request 
                httpResponse = await httpClient.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead);
                httpResponse.EnsureSuccessStatusCode();
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
            }
        }
    }
}

На данном этапе у меня возник вопрос в следующем: как сохранить состояния toggle swich и textbox при переходах на другие страницы (page) приложения? Я так полагаю, что при переходах на страницу, необходимо считывать текущее состояние пинов с arduino, и соответственно в самом приложении уже выставлять тумблеры. Для того чтобы лучше понять вопрос, прилагаю видео. https://vk.com/video28254485_456239083 и https://vk.com/video28254485_456239082 И вроде бы простое решение должно быть, но к сожалению погуглив, так его и не нашел.
Если не сложно, прошу помощи. Заранее Всех благодарю. Спасибо :)

mag155
Offline
Зарегистрирован: 21.12.2017

Всем доброго времени суток выручайте не могу попедить функцию millis . Напишиет скетч чтоб когда нажимаю кнопку диод загорался с выдержкой времени и очень прошу прокоментируйте скетч зараннее всем огромная благодарность.

fake
fake аватар
Offline
Зарегистрирован: 18.08.2017

Отличный проект,я сам не умею,вот бы кто-то с опытом вызвался воплотить что-то подобное для меня. Может знаете проверенных? Буду благодарен за рекомендацию!

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

mag155 пишет:

Всем доброго времени суток выручайте не могу попедить функцию millis .

Функция millis() не предназначена для того, чтоб ее педить. Ищи другую.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

DetSimen пишет:

Функция millis() не предназначена для того, чтоб ее педить. Ищи другую.

millis() может и иск вчинить за харрасмент! Сейчас модно.

georgiev-ruslan
Offline
Зарегистрирован: 31.10.2016

Добрый день всем! К сожалению после долгих дней изучения и поисков, удалось только заставить arduino отвечать на текущее состояние о пинах в serial port. Например, есть две команды через GET запрос: "0" (выключить) и "1" (включить). В данном случае они работают исправно. В скетче для arduino прописал, что если есть GET запрос "2" (состояние пина), то его необходимо отправить в serial port. Ответ о том, что включен пин, или выключен - пришёл. Но, как же всё таки послать из arduino get запрос непосредственно в UWP, и получить в UWP эту команду о состоянии? К сожалению, не могу разобраться....



кусочек скетча на ардуино выглядит так:

if (req.indexOf("/gpio1/0") != -1) { 
val1 = 0; 
ledreq = 1;
}
else if (req.indexOf("/gpio1/1") != -1) { 
val1 = 1; 
ledreq = 1;
}
else if (req.indexOf("/gpio1/2") != -1) { // цифра 2 - запрос на состояние, цифра 1 - указанный пин
int val = digitalRead(5);
Serial.println(val);
if (val == 2) { // если светодиод не горит
... // отсылаем команду на выключение тумблера
} else { // если светодиод горит
... // отсылаем команду на включение тумблера
}
}

команды включения и выключения выглядят так: https://192.168.1.178/gpio1/0 



Вслед за этим возник ещё очень сложный для меня вопрос: при переходе на страницу у меня должен быть вызван обработчик, в котором как раз и должно быть прописано считывание текущего состояния с ардуино... и тут я совсем запутался...

georgiev-ruslan
Offline
Зарегистрирован: 31.10.2016

Прошу прощения за то, что повторяюсь, но погуглив, к сожалению так и не смог понять, как arduino в качестве сервера отсылает ответ на get запрос клиенту. (в данном случае UWP приложение). Если отослать в браузере строку: http://192.168.1.178/gpio1/2 то состояние пина отобразится в serial port. Мне же необходимо это реализовать через ответ GET запроса, чтобы потом получить этот ответ в приложении и обработать его на включение\выключение тумблера в C#. Строки 13 и 15 на скрине.

Полный скетч на arduino прилагаю во вложении: https://yadi.sk/d/uIXR2Ux13S8T8G

smart_pic
Offline
Зарегистрирован: 17.04.2016

1. Для проекта предусмотреть отдельное помещение. У вас это серверная . В Серверной два шкафа размером с нормальный холодильник 19" формата. В одном монтируется слаботочка, в другом все, что относится к 220В. Выбрать для управления помехозащищенные интерфейсы управления.

2. Монтаж вести по схеме точка-серверная. Никаких распределительных коробок по сети 220В и слаботочным цепям. Лампочка-серверная : Выключатель-серверная: розетка-серверная. аналогично и слаботочка. Все провода выводятся на клемные колодки на ДИН рейку в шкафах.

3. По мере продвижения проекта переводим ручное управление на автоматизацию. Все необходимые коммутации делаем в шкафу.

Есть еще один вариант: сделать до последних мелочей продуманный проект(за свою бытность я таких не видел) и все вести строго по проекту и пропадать на объекте днями и ночами следя за всем от возведения стен до окончательной отделки.

Или пойти по предложенному пути немного затратному по кабелю, но очень гибкому варианту. Часть работ всегда можно возложить на электрика и монтажника.

 

georgiev-ruslan
Offline
Зарегистрирован: 31.10.2016

smart_pic: Благодарю Вас за нужную информацию. Это действительно очень полезно и обязательно к выполнению для реализации проекта!

Итак, на сегодняшний момент мне удалось достичь правильного положения выключателей на странице в разделах приложения. Если в комнате горит освещение, то и элемент "тумблер" должен быть во включённом положении. Но если свет не горит, следовательно "тумблер" должен быть выключен. Раньше мне не удавалось сохранять положение элементов на странице в приложении (посты #17, #18). Отталкивался я от того, что мне необходимо при загрузке страницы (или при переходе со страницы на страницу) считывать состояние пинов и в соответствии с этим, переводить "тумблер" во включённое\выключенное состояние.

Пришла идея отдельно записывать положение "тумблеров" в память приложения. Каждое Windows Store-приложение имеет доступ к своему изолированному хранилищу, в котором можно хранить файлы и настройки. Изолированное хранилище приложения содержит папку Local Files. Получается, что когда мы включаем или выключаем "тумблер", его состояние записывается в локальное хранилище (AppData\Local Files) пользователя операционной системы Windows.

Итак, для того, чтобы работать с локальным хранилищем в net.core приложении, нам необходимо подключить директиву.

using Windows.Storage;

Ну и немножко пример кода странички с коментариями о том, как реализуется проверка состояния переключателя, управление переключателем, отправка команд get запросом в приложении UWP:
 

public sealed partial class Page001 : Page
    {
        public Page001()
        {
            this.InitializeComponent();
            this.Loaded += Page_Loaded; // действие при загрузке страницы
        }

        // Сбор состояния всех переключателей на странице при ручном управлении
        private async void Page_Loaded(object sender, RoutedEventArgs e) // проверка состояния датчиков при загрузке страницы
        {
            string url = string.Format("http://10.10.20.1/gpio1/2"); int state = 3;
            SendCommand(url);
            // Сбор состояния переключателей: toggleSwitch001Light
            var val1 = (string)ApplicationData.Current.LocalSettings.Values["toggleSwitch001Light"];
            if (val1 == "On")
            {
                toggleSwitch001Light.IsOn = false;
                
                if (sender == toggleSwitch001Light)
                {
                    toggleSwitch001Light.IsOn = !toggleSwitch001Light.IsOn;
                }
                else toggleSwitch001Light.IsOn = true;
            }
            if (val1 == "Off")
            {
                toggleSwitch001Light.IsOn = true;
                if (sender == toggleSwitch001Light)
                {
                    toggleSwitch001Light.IsOn = !toggleSwitch001Light.IsOn;
                }
                else toggleSwitch001Light.IsOn = false;
            }
// Переключатель: toggleSwitch001Light
        private void toggleSwitch001Light_Toggled(object sender, RoutedEventArgs e)
        {
            string svr = txtIP.Text;
            string url = string.Format("http://10.10.20.1/gpio1/0", svr); int state = 0;
            ApplicationData.Current.LocalSettings.Values["toggleSwitch001Light"] = "Off";
            if (toggleSwitch001Light.IsOn)
            {
                url = string.Format("http://10.10.20.1/gpio1/1", svr); state = 1;
                ApplicationData.Current.LocalSettings.Values["toggleSwitch001Light"] = "On";
            }
            SendCommand(url);
            UpdateStatus(1, state);
        }
// Обновление статуса в текстовом поле о состоянии выключателей
        private void UpdateStatus(int led, int state)
        {
            if (state == 1)
                txtStatus.Text = string.Format("LED {0} is ON", led);
            else
                txtStatus.Text = string.Format("LED {0} is OFF", led);
        }
        // Отправка команд и Get запросов на Arduino платы
        private async void SendCommand(string url)
        {
            HttpClient httpClient = new HttpClient(); var headers = httpClient.DefaultRequestHeaders;
            Uri requestUri = new Uri(url);
            HttpResponseMessage httpResponse = new HttpResponseMessage(); try
            {
                //Send the GET request 
                httpResponse = await httpClient.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead);
                httpResponse.EnsureSuccessStatusCode();
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
            }
        }

 

mag155
Offline
Зарегистрирован: 21.12.2017

Всем доброго времени суток. Подскажите, каким образом можно с помощью переменного резистора менять время в millis.Например жмем на кнопку, проходит какоето врямя зажигается диод, крутим переменник, жмем на кнопку и диод зажигается через другой промежуток времени?

bwn
Offline
Зарегистрирован: 25.08.2014

С помощью analogRead и функции map. Подробности в подходящей для этого теме.

mag155
Offline
Зарегистрирован: 21.12.2017

Что делает map я понимаю, вот как преобразовать именно в число в millis? Если не сложно киньте ссылку на подходящюю тему .

bwn
Offline
Зарегистрирован: 25.08.2014

mag155 пишет:

Что делает map я понимаю, вот как преобразовать именно в число в millis? Если не сложно киньте ссылку на подходящюю тему .

Подробности в подходящей для этого теме. Если вы не нашли ничего подходящего, просто заводите свою (в данном случае раздел "общий или программирование", с осмысленным названием, типа "Как преобразовать аналоговое значение  в интервал для миллис." и выкладываете туда что пытались сделать и какие вопросы возникли. Денег ведь за это не берут, ну зачем постить там, где и речи про это нет.

mag155
Offline
Зарегистрирован: 21.12.2017

Спасибо понял.

mag155
Offline
Зарегистрирован: 21.12.2017

Создал новую тему не могли бы вы там мне ответить?

georgiev-ruslan
Offline
Зарегистрирован: 31.10.2016

Итак, прошло очень много времени со дня моей последней публикации. Вот собственно результат одной из комнат. Проработаны тумблеры устройств. Каждый тумблер посылает команды включения и выключения по ip адресу на arduino по локальной сети. Также проработаны сценарии, которые включают или выключают тумблеры, которые в свою очередь управляют устройствами в комнате. Колличество тумблеров в каждой комнате разное. Совсем скоро буду заказывать на одну комнату партию плат arduino и компонентов с ali express, чтобы всё проверить в деле. Помимо тумблеров управления на странице будут отображаться температурные показатели, в зависимости от которых будут регулироваться контуры отопления. Для наглядности также добавил график на каждую страницу помещения. На самом плане для лучшего восприятия добавил некоторые chekbox`ы, которые также выполняют функцию тумблеров. Картинку плана обязательно переделаю, чтобы смотрелась лучше, пущю под рендер. Рядом с планом будет располагаться изображение с ip камеры в помещении (где сейчас находится кнопочка "Hover..."). Осталось только её заказать вместе с компонентами. Ну и последнее, в приложение добавил отображение погоды от "Яндекс", которое находится на отдельной страничке... 

wagin221
Offline
Зарегистрирован: 27.09.2017

Привет единомышленник. То-же тварю подобное на C# Visual Studio под Win7+ arduino mega (4 шт.), а в на чем кодите?

georgiev-ruslan
Offline
Зарегистрирован: 31.10.2016

wagin221: Приветствую, я к сожалению новичок в программировании. Связка: Arduino Nano - Ethernet Shild - GET запросы - Приложение UWP на С#. Удалось вкл/выкл тумблеры в ручную и по времени с сохранением состояния выключателей. Сейчас пытаюсь сделать графики (связка arduino - csv - c#) Не могу пока сделать так, чтобы строился график по данным с csv файла.... txt читает без проблем с одним значением... Но нужно привязать как то "время,значение". Или с помощью текстового файла привязывать нужное значение к времени с очищением всех строк в файле в конце дня. Например: 

ChartInfo.Add(new ChartData() { DataName = "00:00", DataValue = y0 });
                    ChartInfo.Add(new ChartData() { DataName = "01:00", DataValue = y1 }); // "у" переменные значений с датчиков
                    ChartInfo.Add(new ChartData() { DataName = "02:00", DataValue = y2 });
                    ChartInfo.Add(new ChartData() { DataName = "03:00", DataValue = y3 });
                    //...
                    ChartInfo.Add(new ChartData() { DataName = "23:00", DataValue = y23 });

 

wagin221
Offline
Зарегистрирован: 27.09.2017

Я тоже новичек в програмировании, но потихоньку ковыряюсь. Тоже с графиками затык есть, Пока что сделал так. Каждую минуту снимаются показания с  датчика Dallas и сохраняются в текстовике в столбик. Текстовик называется текущей датой, допустим 11 май 2017г.txt. В строку заносится в таком формате 8*45*24, где 8- это текущий час, 45- текущая минута, 24-текущая температура, а звездочка это разделитель, что бы проще было распарсить при извлечении из ткстовика в переменную.

Ну а дальше извлеченные данные в переменные скажем int a = 8; int b =45; int c =24; по идее время 8-45, это координаты оси X. Их преобразуем в минуты, т.е 8 часов это 8*60=480 минут да + 45 мин итого координата x=525, а y =24. Далее строится первая точка по этим координатам в chart. Через минуту когда в текстовике появится следующая запись т.е вторая строка, считываем ее и строится вторая точка. У меня пока вот так работает, можно конечно и напрямую в переменную время писать, но в случае перезагрузки график обнулиться. Чуть позже скину фото моего интерфейса.

 

georgiev-ruslan
Offline
Зарегистрирован: 31.10.2016

wagin221: здравствуйте. я к сожалению не могу понять как скачать текстовый файл с sd карты arduino на компьютер через GET, чтобы потом его распарсить... В самом приложении на С# могу построить график, координаты которого берутся с текстового файла. (файл без названия даты... как реализовать запись и чтение нового файла каждый день - я пока не знаю).

wagin221
Offline
Зарегистрирован: 27.09.2017

wagin221
Offline
Зарегистрирован: 27.09.2017

wagin221
Offline
Зарегистрирован: 27.09.2017

georgiev-ruslan
Offline
Зарегистрирован: 31.10.2016

wagin221: я так понимаю, вы сами указываете путь к нужному файлу лога при нажатии кнопки "выбери день". А вот как вы вытягиваете файл лога из arduino? Я так понимаю Arduino подключена через Serial Port... В моём случае используется Ethernet Shild... В лучшем случае хотелось бы вытягивать с sd карточки текстовый файл лога по сети через ethernet...
ps: проект прикольный, очень интересно! 

 

wagin221
Offline
Зарегистрирован: 27.09.2017

Дело в том что у меня ардуина общается с компом по USB-SerialPort, и  на стене постоянно включенный компьютер, это и есть мозги, а Я просто могу заходить по удаленке на него с работы, или смартфона, и управлять, и контролировать. Все датчики разведены витой парой по комнотам. Короче все на проводах. Это третья версия моей софтины, сейчас в процессе написания, основная часть готова. Жду запчасти и буду внедрять в дом. Вторая версия отработала зиму-лето без проблем. Ардуина только снимает показания с датчиков, по запросу компьютера, а компьютер уже обрабатывает.

Тему стараюсь вести здесь https://ввв.forumhouse.ru/threads/463167/

Присоединяйтесь.

 

georgiev-ruslan
Offline
Зарегистрирован: 31.10.2016

wagin221: обязательно присоединюсь! Мне очень интересно! Спасибо Вам! Сегодня покапавшись в интернете, нарыл интересный скетч, в котором отображаются папки и файлы, находящиеся на sd карточке. Смысл прост, заходим на Arduino по IP адресу. Видим список всего, что есть на SD карте. При клике (указании ссылки в браузере - нужный файл очень легко скачивается на компьютер). Собственно, сам скетч выглядит так:

/*
 * SDWebBrowse.ino
 *
 * This sketch uses the microSD card slot on the a WIZ5500 Ethernet shield
 * to serve up files over a very minimal browsing interface
 *
 * Some code is from Bill Greiman's SdFatLib examples, some is from the
 * Arduino Ethernet WebServer example and the rest is from Limor Fried
 * (Adafruit) so its probably under GPL
 *
 * Tutorial is at https://learn.adafruit.com/arduino-ethernet-sd-card/serving-files-over-e...
 * 
 */
 
#include <SPI.h>
#include <SD.h>
#include <Ethernet.h>

/************ ETHERNET STUFF ************/
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };  // change if necessary
byte ip[] = { 192, 168, 1, 177 };                     // change if necessary
EthernetServer server(80);

/************ SDCARD STUFF ************/
#define SDCARD_CS 4
File root;

#if defined(ESP8266)
  // default for ESPressif
  #define WIZ_CS 15
#elif defined(ESP32)
  #define WIZ_CS 33
#elif defined(ARDUINO_STM32_FEATHER)
  // default for WICED
  #define WIZ_CS PB4
#elif defined(TEENSYDUINO)
  #define WIZ_CS 10
#elif defined(ARDUINO_FEATHER52)
  #define WIZ_CS 11
#else   // default for 328p, 32u4 and m0
  #define WIZ_CS 10
#endif

// store error strings in flash to save RAM
#define error(s) error_P(PSTR(s))

void error_P(const char* str) {
  Serial.print(F("error: "));
  Serial.println(str);

  while(1);
}

void setup() {
  Serial.begin(115200);
  while (!Serial);      // For 32u4 based microcontrollers like 32u4 Adalogger Feather
 
  //Serial.print(F("Free RAM: ")); Serial.println(FreeRam());  

  if (!SD.begin(SDCARD_CS)) {
    error("card.init failed!");
  } 
  
  root = SD.open("/");
  printDirectory(root, 0);
  
  // Recursive list of all directories
  Serial.println(F("Files found in all dirs:"));
  printDirectory(root, 0);
  
  Serial.println();
  Serial.println(F("Done"));
  
  // Debugging complete, we start the server!
  Serial.println(F("Initializing WizNet"));
  Ethernet.init(WIZ_CS);
  // give the ethernet module time to boot up
  delay(1000);
  // start the Ethernet connection
  // Use the fixed IP specified. If you want to use DHCP first
  //   then switch the Ethernet.begin statements
  Ethernet.begin(mac, ip);
  // try to congifure using DHCP address instead of IP:
  //  Ethernet.begin(mac);
  
  // print the Ethernet board/shield's IP address to Serial monitor
  Serial.print(F("My IP address: "));
  Serial.println(Ethernet.localIP());

  server.begin();
}

void ListFiles(EthernetClient client, uint8_t flags, File dir) {
  client.println("<ul>");
  while (true) {
    File entry = dir.openNextFile();
   
    // done if past last used entry
     if (! entry) {
       // no more files
       break;
     }

    // print any indent spaces
    client.print("<li><a href=\"");
    client.print(entry.name());
    if (entry.isDirectory()) {
       client.println("/");
    }
    client.print("\">");
    
    // print file name with possible blank fill
    client.print(entry.name());
    if (entry.isDirectory()) {
       client.println("/");
    }
        
    client.print("</a>");
/*
    // print modify date/time if requested
    if (flags & LS_DATE) {
       dir.printFatDate(p.lastWriteDate);
       client.print(' ');
       dir.printFatTime(p.lastWriteTime);
    }
    // print size if requested
    if (!DIR_IS_SUBDIR(&p) && (flags & LS_SIZE)) {
      client.print(' ');
      client.print(p.fileSize);
    }
    */
    client.println("</li>");
    entry.close();
  }
  client.println("</ul>");
}

// How big our line buffer should be. 100 is plenty!
#define BUFSIZ 100

void loop()
{
  char clientline[BUFSIZ];
  char name[17];
  int index = 0;
  
  EthernetClient client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean current_line_is_blank = true;
    
    // reset the input buffer
    index = 0;
    
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        
        // If it isn't a new line, add the character to the buffer
        if (c != '\n' && c != '\r') {
          clientline[index] = c;
          index++;
          // are we too big for the buffer? start tossing out data
          if (index >= BUFSIZ) 
            index = BUFSIZ -1;
          
          // continue to read more data!
          continue;
        }
        
        // got a \n or \r new line, which means the string is done
        clientline[index] = 0;
        
        // Print it out for debugging
        Serial.println(clientline);
        
        // Look for substring such as a request to get the file
        if (strstr(clientline, "GET /") != 0) {
          // this time no space after the /, so a sub-file!
          char *filename;
          
          filename = clientline + 5; // look after the "GET /" (5 chars)  *******
          // a little trick, look for the " HTTP/1.1" string and 
          // turn the first character of the substring into a 0 to clear it out.
          (strstr(clientline, " HTTP"))[0] = 0;
 
          if(filename[strlen(filename)-1] == '/') {  // Trim a directory filename
            filename[strlen(filename)-1] = 0;        //  as Open throws error with trailing /
          }
          
          Serial.print(F("Web request for: ")); Serial.println(filename);  // print the file we want

          File file = SD.open(filename, O_READ);
          if ( file == 0 ) {  // Opening the file with return code of 0 is an error in SDFile.open
            client.println("HTTP/1.1 404 Not Found");
            client.println("Content-Type: text/html");
            client.println();
            client.println("<h2>File Not Found!</h2>");
            client.println("<br><h3>Couldn't open the File!</h3>");
            break; 
          }
          
          Serial.println("File Opened!");
                    
          client.println("HTTP/1.1 200 OK");
          if (file.isDirectory()) {
            Serial.println("is a directory");
            //file.close();
            client.println("Content-Type: text/html");
            client.println();
            client.print("<h2>Files in /");
            client.print(filename); 
            client.println(":</h2>");
            ListFiles(client,LS_SIZE,file);  
            file.close();                   
          } else { // Any non-directory clicked, server will send file to client for download
            client.println("Content-Type: application/octet-stream");
            client.println();
          
            char file_buffer[16];
            int avail;
            while (avail = file.available()) {
              int to_read = min(avail, 16);
              if (to_read != file.read(file_buffer, to_read)) {
                break;
              }
              // uncomment the serial to debug (slow!)
              //Serial.write((char)c);
              client.write(file_buffer, to_read);
            }
            file.close();
          }
        } else {
          // everything else is a 404
          client.println("HTTP/1.1 404 Not Found");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<h2>File Not Found!</h2>");
        }
        break;
      }
    }
    // give the web browser time to receive the data
    delay(1);
    client.stop();
  }
}


void printDirectory(File dir, int numTabs) {
   while(true) {
     File entry =  dir.openNextFile();
     if (! entry) {
       // no more files
       break;
     }
     for (uint8_t i=0; i<numTabs; i++) {
       Serial.print('\t');
     }
     Serial.print(entry.name());
     if (entry.isDirectory()) {
       Serial.println("/");
       printDirectory(entry, numTabs+1);
     } else {
       // files have sizes, directories do not
       Serial.print("\t\t");
       Serial.println(entry.size(), DEC);
     }
     entry.close();
   }
}

Теперь мне необходимо к вышеизложенному скетчу добавить следующую задачу: заставить писать показания с датчиков в текстовый файл на SD карту. (В идеале: совместить два скетча вместе), чтобы можно было скачивать нужный лог с ардуино. Запись лога на SD карту происходит таким путём:
 

#include <Ethernet.h>
#include <SPI.h>
#include <SD.h>

const int chipSelect = 4;

#define SWITCH_TO_W5100 digitalWrite(4,HIGH); digitalWrite(10,LOW)
#define SWITCH_TO_SD digitalWrite(10,HIGH); digitalWrite(4,LOW)
#define ALL_OFF digitalWrite(10,HIGH); digitalWrite(4,HIGH)

float refresh_rate = 0.0;  // Задержка обновления данных
long id = 1;               // Переменная для счетчика строк

File root;
EthernetClient client;
byte server[] = { 10,10,20,1 };
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip ( 10,10,20,1 );
 
void setup()
{
  SWITCH_TO_W5100;
  pinMode(4, OUTPUT);
  pinMode(10, OUTPUT);
  Serial.begin(9600);
  Ethernet.begin(mac,ip);
  Serial.println("Ethernet start");
  Serial.print("Initializing SD card...");
  SWITCH_TO_SD;
  pinMode(10, OUTPUT);
  if (!SD.begin(4)) Serial.println("initialization failed!");
  else Serial.println("initialization done.");
  ALL_OFF;
}
 
void loop()
{
  delay(3000);
  readPage();
}
 
void readPage()
{
Serial.println("connecting...");  //конектимся к серверу по 80 порту
  if (client.connect(server, 80)) Serial.println("connected");
client.stop();
 Serial.println("Disconnected");
 if (!SD.begin(chipSelect)) {
        Serial.println("Card failed, or not present");
        return;
    }

  // создать строку для сборки данных в лог:
  String dataString = "";
  String dataStringT = "";
  String dataStringH = "";

  // прочитать два датчика и добавить данные к строке:
  
  {
    int sensor1 = analogRead(A1);
    int sensor2 = analogRead(A2);
    
    //dataString += String("temperature") + ":" + String(sensor1) + "\n" + String ("humidity") + ":" + String(sensor2) + "\r"; // ключи переноса строки \r файл \n сериал порт

    dataString = String("temperature") + ":" + String(sensor1) + "\n" + String("humidity") + ":" + String(sensor2) + "\r";
    dataStringT = String(sensor1) + "\n" "\r";
    dataStringH = String(sensor2) + "\n" "\r";
}

// открыть файл. обратите внимание, что за раз может быть открыт только один файл,
  // поэтому вы должны закрыть его перед открытием другого.
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // если файл доступен, то записать в него:
  if (dataFile) 
  {
    dataFile.println(dataString);
    dataFile.close();
    // вывести строку и в последовательный порт:
    Serial.println(dataString);
    Serial.flush();
  }
  // если файл не открыт, вывести сообщение об ошибке:
  else 
  {
    Serial.println("error opening datalog.txt");
  }

  // открыть файл. обратите внимание, что за раз может быть открыт только один файл,
  // поэтому вы должны закрыть его перед открытием другого.
  File dataFileT = SD.open("datalogT.txt", FILE_WRITE);

  // если файл доступен, то записать в него:
  if (dataFileT) 
  {
    dataFileT.println(dataStringT);
    dataFileT.close();
    // вывести строку и в последовательный порт:
    Serial.println(dataStringT);
    Serial.flush();
  }
  // если файл не открыт, вывести сообщение об ошибке:
  else 
  {
    Serial.println("error opening datalogT.txt");
  }


    // открыть файл. обратите внимание, что за раз может быть открыт только один файл,
  // поэтому вы должны закрыть его перед открытием другого.
  File dataFileH = SD.open("datalogH.txt", FILE_WRITE);

  // если файл доступен, то записать в него:
  if (dataFileH) 
  {
    dataFileH.println(dataStringH);
    dataFileH.close();
    // вывести строку и в последовательный порт:
    Serial.println(dataStringH);
    Serial.flush();
  }
  // если файл не открыт, вывести сообщение об ошибке:
  else 
  {
    Serial.println("error opening datalogH.txt");
  }
 Serial.println("done!");

 //Increment ID number
 id++;
 
 delay(refresh_rate);

}

Теперь необходимо как нибудь совместить эти два скетча вместе, чтобы и запись логов была на SD карту, и можно было спокойно скачивать лог с SD карты на компьютер.  Парсинг данных в текстовом файле через C# и рисование графика уже сделано. :)