GSM устройство управления котлами Webasto и не только

Dushman7776
Offline
Зарегистрирован: 13.01.2019

Сделал задержку 4 секунды вместо 3.5 , и глюк прошел вроде, глюк себя проявлял при снятии аккума или после подключения питания после прошивки, как будто синхронизация модема с друиной не происходила или может dc-dc медленно раскачивается.

MaksVV
Offline
Зарегистрирован: 06.08.2015

YuriL пишет:
А какой предохранитель ставил? Можно маркировку, размер?

Детальки едут, остальное надо докупать)

Такие самовосстанавливаемые смд в размере 1206. Взял на 1,5А.  напряжение у них до 25В. Можно по 12В линии поставить на 2А, а по 4В линии на 1,5. Я везде на 1,5А поставил, т.к. купил только их. Работает. 

Весь список деталей пост #254

MaksVV
Offline
Зарегистрирован: 06.08.2015

vgk_com, ну как пришли платы ? собрал девайс?   готовлю обновление скетча. в планах добавить взаимодействие смартфона с девайсом по MQTT протоколу, то бишь по GPRS. реагирует так гораздо быстрее смс ок. и приятнее пользоваться. к тому же дешевле. но вот скетч усложняется конечно, не знаю влезет ли все. нужно оптимизировать. 

MaksVV
Offline
Зарегистрирован: 06.08.2015

и жду отчета о последнем скетче от Dushman7776, как работает?

Dushman7776
Offline
Зарегистрирован: 13.01.2019

Завтра отвечу , я его только сегодня в новую промини залил , завтра потестю. А глюк со снятием аккумулятора повторился, снимал аккум. на подзарядку, когда поствил решил проверить. отправил смс запрос состояния, отчет о том что смс принята пришел , а в ответ опять тишина, разъем питания передёрнул и все заработало, не помогла значит установка в 4 секунды вместо 3.5. Не могу понять почему так происходит, по конструктиву все как у вас, даже преобразователь такой же , реле правда немного другое на проводках под под модемом на боку приклеено, а так все как у вас. Ну и разъема у меня нет такого , все на проводах нуружу выведено, но у там всего  то на кнопку , на датчики и 3 провода питание и wbus. 

Dushman7776
Offline
Зарегистрирован: 13.01.2019

Это вообще крутяк крутой будет , через тырнет лучше , а то смски вчерашний день , а так вашему творению не будет конкурента, с его возможностями, я ни во одном аналогичном  устройсве не видел функции чтения и стирания ошибок. Да и смски нынче дороги , в моем тарифе на симкоме всего 200 смс но зато 5 гигов тырнета, по протоколу MQTT  его на все хватит, на личном смартфоне 25 гигов в месяц, а так плачу еще за безлим смс на своем смартфоне и за безлим на симкоме.

MaksVV
Offline
Зарегистрирован: 06.08.2015

ага. причем на протокол MQTT даже при постоянном обмене данными раз в минуту, нужно максимум 50 Мб (Мегабайт!, Карл) в месяц - копейки. Единственный совсем не большой минус - это потребление тока увеличится аж целых на 3...4 мА, от части даже из за того, что сигнальный светодиод на сим800 при открытой GPRS сессии очень часто мигает. 

Dushman7776
Offline
Зарегистрирован: 13.01.2019

Скетч 3.65 работает всё, по крайней мере то что относиться к котлу, и даже глюка ,описанного ранее, не заметил. Ну и прописку далласов не проверял. 

Dushman7776
Offline
Зарегистрирован: 13.01.2019

Сегодня обновился gsm trinket и теперь не отправляет и не принимает сообщения , пишет что запрещено новым законом, где взять старую версию?

vgk_com
Offline
Зарегистрирован: 02.03.2017

Платы пришли, пока не собирал. На улице уже почти тепло, вебаста не нужна. Буду готовиться к следующей зиме. Да и реле с разъемами еще не пришло с Китая. Уже больше месяца идут, но уже в России. На счет mqtt это классно, но наверное нужно переходить на другую платформу, памяти маловато.

Dushman7776
Offline
Зарегистрирован: 13.01.2019

скачал старую версию gsm tinker 4.01 на 4пда , установил и запретил обновляться. Все работает по старому , долбаный гугл , будь он проклят со своими политиками.

MaksVV
Offline
Зарегистрирован: 06.08.2015

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

Dushman7776
Offline
Зарегистрирован: 13.01.2019

Я сразу не сообразил , у меня такая же надпись вылазила , я поставил галку и закрыл сообщение , я подумал что полная версия платная . читать наверное разучился .

MaksVV
Offline
Зарегистрирован: 06.08.2015

заметил проблему с хардовым ресетом SIM800 при помощи реле. Еcтественно ресет я не ждал, а специально инициировал. Дело в том, что при ресете реле размыкает питание сим800 на 6 секунд,тут все гуд, но вот когда реле обратно замыкается, подавая вновь питание на сим800, происходит почему-то также  ресет самой ардуины. 

также отмечено, что если вытащить сим800  (т.е. реле просто щёлкает впустую) ардуина уже НЕ ресетится, также ардуино НЕ ресетится если просто вытащить сим800 и вставить обратно (т.е. НЕ в момент процедуры  ресета сим800). Еще пробовал вытащить сим800 в момент процедры ресета, когда реле прерывает питание, но вставить уже чуть чуть позже замыкания реле, то тоже ардуино НЕ ресетится. 

  Думал что:

- вступая в работу, сим800 в начале потребляет много и происходит просадка по питанию ардуино (она питается от тех же 4В). Померил этот момент осциллографом - всё четко,  линия 4В даже не шелохнётся. 

- выносная антенна даёт какието наводки на ардуино, отключал - не помогает;

Попробую ещё померить осликом, что на пине "ресет" дуни и контактах рх тх в момент проявления косяка. Если у кого есть какие соображения по причинам просходящего, рад выслушать. 

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

потратил часа два чтобы найти данный косяк с незапланированным рестартом ардуины. Все таки ардуина ресетилась из-за нехватки питания. Хотя напряжение не проседает (причём совсем), видимо по току идёт нехватка. Припаял ещё один кондёр 470мФ прямо к ноге VCC ардуино и проблема ушла. Надо опять плату модернизировать)) А на готовых платах опять колхоз с конденсатором будет. 

Dushman7776
Offline
Зарегистрирован: 13.01.2019

Может идет какой нибудь кратковременный выброс по питанию, а доп. конденсатор его гасит, потому что если напряжение не проседает совсем ,то и ток не должен проседать , или искровая помеха от реле , без нагрузки ее не будет, как то была подобная проблема , долго искали почему на ниссан эксперт ошибка вылазила , по ДПКВ, а проблема была в игольчатом выбросе от свечей зажигания новых , но не тех что надо , а наш осцыллограф не мог эту иголку поймать толком , кое как ее заметил.

MaksVV
Offline
Зарегистрирован: 06.08.2015

ну возможно. Я вроде растягивал осциллограмму. Иголок не было. Хотя осцил да, дешевый у меня. 

osa71aso
Offline
Зарегистрирован: 27.05.2019

 с webasto все хорошо. а как быть с eberspacher. можно ли им управлять и в каком обьеме?

MaksVV
Offline
Зарегистрирован: 06.08.2015

если речь про hydronic 1  - управлять можно и по шине и по плюсу. Управляя по шине, лишаемся возможности получать диагностические параметры, поэтому рентабельнее включать по плюсу, а по шине вытягивать данные. По другим еберам не разбирался. 

Всё это ещё НЕ реализовано в сабжевом девайсе. 

Протокол Ebera 1 я исследовал раньше. Инфа тут

osa71aso
Offline
Зарегистрирован: 27.05.2019

в моем случае котел D5wz. он вроде бы первый hydrinic. я его хочу из догревайки превратить в полноценный предпусковой и управлять пуском/стопом дистанционно. что в данном возможно по плюсу?

MaksVV
Offline
Зарегистрирован: 06.08.2015

а инфу то уже собрали как превратить в предпусковой? Выше по ссылке самый лучший форум по печкам. Штудируйте. 

Dushman7776
Offline
Зарегистрирован: 13.01.2019

А как обстоят дела с MQTT? И с новой версией вашего девайса. Лето пролетит очень быстро , пора начинать готовить сани.

MaksVV
Offline
Зарегистрирован: 06.08.2015

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

MaksVV
Offline
Зарегистрирован: 06.08.2015

Примерно так будет выглядеть панель управления

vgk_com
Offline
Зарегистрирован: 02.03.2017

Классно выглядет, а программка для андроида или IOS. 

MaksVV
Offline
Зарегистрирован: 06.08.2015

mqtt dash. Android. На ios может тоже есть, не знаю. 

Dushman7776
Offline
Зарегистрирован: 13.01.2019

Класс, а по железу будет что-нибудь меняться ? Нужно что-нибудь заказывать у братьев китайцев?

MaksVV
Offline
Зарегистрирован: 06.08.2015

Нет , кроме косяка озвученного чуть выше , вроде пока нечего менять

Секешфехервар
Секешфехервар аватар
Offline
Зарегистрирован: 06.09.2018

Выкинул из своей схемы предохранитель полимерный, без него модуль связи работает стабильнее.

Секешфехервар
Секешфехервар аватар
Offline
Зарегистрирован: 06.09.2018

MaksVV пишет:

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

 Как вариант можно использовать DTMF для управления..

Pashok3D
Offline
Зарегистрирован: 20.01.2019

ПОчти конец лета  . можно готовить сани .   

Так и есть один котел на 99той ,  и еще один ево .    уже и прикупл осцилограф .

dimabos09
Offline
Зарегистрирован: 14.01.2019

Вечер добрый уважаемый MaksVV, собрал сей девайс, при тестировании не мог получить ответы на отправленнве запросы, пока не додумался что причина в том что мой номер телефона на одну цифру короче (11знаков) попробывал другой номер (12знаков) всё работает идеально. Есть ли вожможность сделать изменения в коде чтобы номер телефона не был привязан к количеству знаков.

dimabos09
Offline
Зарегистрирован: 14.01.2019

?

MaksVV
Offline
Зарегистрирован: 06.08.2015

да можно. какой скетч используете?

MaksVV
Offline
Зарегистрирован: 06.08.2015

v3.66 , это 3,65 переделанный под 11 значный номер тел. 

char ver[] = "Firmware 3.66";    // версия прошивки



//----------------------------------название ячеек еепром----------------------------------------------------------------
#include <EEPROM.h>
enum Cells {
ResetNumber_cell,      //0
TimeWebasto_cell,      //1
ProtocolSTART_cell,    //2
StartByte_cell,        //3
ProtocolSTATUS_cell,   //4
Heater_cell,           //5
delta_cell,            //6
TelNumber1_cell =20,  //20
TelNumber2_cell =40,  //40
DallasAddr_cell =60   //60
};


//-------------------------------------для voltmetr-----------------------------------------------------------------------
                                   
float vout = 0.0;      // Напряжение на входе аналового входа
float Vpit = 0.0;      // Измеряемое напряжение на выходе ИБП
  int volt = 0;        // Напряжение на входе АЦП


//------------------- распиновка ног ардуино (плата весий 8.5-8.8)--------------------------------------------------------

#define OutWebasto_12V      2  // это +12В выход потенциала вкл/выкл вебасто (напрямую к котлу без таймера). 
#define Dallas_pin          3  // пин шины OneWire для датчиков даллас
#define DopOn               4  // сюда доп канал от сигналки на включение вебасто
#define DopOff              5  // сюда доп канал от сигналки на выключение вебасто
#define Ohrana              6  // Сюда состояние охраны сигналки
#define Trevoga             7  // Сюда состояние тревоги
#define IGN                 8  // Сюда состояние зажигания
#define Sost                9  // Сюда состояние вебасто (+12В когда работает)
#define ResetGSM           12  // пин ресета GSM подключен к реле, разрывающее питание модуля. 
#define Eng                14  // (А0) Сюда состояние работы ДВС
#define StatusWebastoLED   15  // (А1) пин LED  индикация включенности котла
#define StartButtonpin     16  // (А2) пин тактовой кнопки вкл/выкл котла 
#define DTR                17  // пин (А3), управляющий энергосберегающим режимом GSM модуля
#define StartEng           18  // (A4) это импульсный минусовой выход вкл/выкл ДВС. подключать на вход событий сиги.
#define OutWebasto_GndImp  19  // (A5) это импульсный минусовой выход вкл/выкл вебасто (к впайке к кнопке таймера).  
#define Voltmeter_pin      A7  // пин, которым измеряем напряжение питания
#define StartButton         0  // программный номер тактовой кнопки вкл/выкл котла 
const bool RelayON =        1; // логика управления реле ресета GSM, в данном случае включается высоким уровнем на пине
#define GSM_RX             10  // пин софт RX Arduino для соединения с TX модуля SIM800
#define GSM_TX             11  // пин софт TX Arduino для соединения с RX модуля SIM800

/*
//------------------- распиновка ног ардуино (плата весий 5)---------------------------------------------------------------

#define Dallas_pin          2  // пин шины OneWire для датчиков даллас
#define OutWebasto_12V      3  // это +12В выход потенциала вкл/выкл вебасто (напрямую к котлу без таймера). 
#define DopOn               4  // сюда доп канал от сигналки на включение вебасто
#define DopOff              5  // сюда доп канал от сигналки на выключение вебасто
#define Ohrana              6  // Сюда состояние охраны сигналки
#define Trevoga             7  // Сюда состояние тревоги
#define StartEng            8  // это импульсный минусовой выход вкл/выкл ДВС. подключать на вход событий сиги.
#define Sost                9  // Сюда состояние вебасто (+12В когда работает)
#define IGN                10  // Сюда состояние зажигания
#define Eng                11  // Сюда состояние работы ДВС
#define OutWebasto_GndImp  12  // это импульсный минусовой выход вкл/выкл вебасто (к впайке к кнопке таймера). 
#define StatusWebastoLED   13  // пин индикация включенности котла
#define ResetGSM           16  // пин ресета GSM (A2) подключен к реле, разрывающее питание модуля. 
#define StartButtonpin     17  // пин тактовой кнопки вкл/выкл котла 
#define DTR                19  // пин (А5), управляющий энергосберегающим режимом GSM модуля
#define StartButton         0  // программный номер тактовой кнопки вкл/выкл котла 
const bool RelayON =        0; // логика управления реле ресета GSM, в данном случае включается низким уровнем на пине
#define GSM_RX             14  // пин софт RX Arduino для соединения с TX модуля SIM800
#define GSM_TX             15  // пин софт TX Arduino для соединения с RX модуля SIM800

*/

//------------------------------------для GSM модуля----------------------------------------------------------------------

#include <SoftwareSerial.h>
      SoftwareSerial SIM800 (GSM_RX, GSM_TX);//Rx, Tx   //UART для соединения с GSM модулем

String currStr = "";
String TelNumber[] = {"", "00000000000", "00000000000", "00000000000"};
byte isStringMessage = 0; 
byte KTOreport = 1;     // флаг кто запросил отчет о запуске котла или ДВС
byte KTOzapros = 0;     // флаг кто запросил баланс или запрос параметров 

uint32_t  prevReset=0;           // для таймера периодичности проверки (командой "АТ")
byte  intervalReset = 15;         // каждые столько мин будет проверка жив ли GSM модуль 
uint32_t  timerWaitOK=0;         // для таймера ожидания ответа после посылки команды "АТ"
bool timerenabledWaitOK=false;   // для таймера ожидания ответа после посылки команды "АТ"
byte NoAnswersGSM=0;             // количество неответов  от GSM модуля
bool gsmOK = 1;                  // флаг есть связь с GSM модулем или нет
bool resettimer = 0;             // для таймера удерживания реле в режиме сброс питания
uint32_t  resetTimer=0;          // для таймера удерживания реле в режиме сброс питания
byte ResetNumber = 0;            // количество ресетов GSM модуля для статистики (хранится в еепром)




//------------------- для шины 1-wire и датчиков DS18B20---------------------------------------------------------------------

#include <OneWire.h>    // библиотека для DS18B20
OneWire ds(Dallas_pin); // датчики DS18B20 на нужный пин

enum TempC {VyhlopC, EngineC, UlicaC, SalonC, size_arrayTemp}; // перечисление нужных температур (в конце размер массива температур)

// ниже соответствие адресов датчиков различным температурам 
byte DS18B20 [size_arrayTemp][10] = {
{0x28, 0xFF, 0xB2, 0xB5, 0xC1, 0x17, 0x05, 0xD1, VyhlopC,  -100}, 
{0x28, 0xFF, 0xD3, 0xE2, 0xC1, 0x17, 0x04, 0x0D, EngineC,  -100}, 
{0x28, 0xFF, 0xF8, 0xBC, 0xC1, 0x17, 0x04, 0x48, UlicaC,   -100},  
{0x28, 0xFF, 0x3F, 0xB7, 0xC1, 0x17, 0x05, 0xF1, SalonC,   -100}
};
byte delta = 50;  // разница температур выхлопа и улицы, выше которой считается, что пламя в котле есть. 

int8_t HeaterC = -100;
//---------------------------для организации W-BUS и различные таймеры-----------------------------------------------------------

#include <Button.h>
Button test;

#define K_LINE Serial      //UART для соединения с шиной котла
#define TX 1    
#define NEED 1
#define READY 10

byte header = 0;           // состояние заголовка 
byte message_size = 0;     // размер тела принимаемого сообщения, кол-во байт

byte j = 2;                // инкремент
byte n = 2;
const byte bufsize = 140;  // размер буфера принятого сообщения
byte buf [bufsize] = {0};  // буфер принятого сообщения
byte checksum = 0;         // контрольная сумма входящего сообщения
uint32_t curmillis = 0;    // снимок системного времени
byte delaybyte_TX = 0 ;    // задержка между байтами отправляемого сообщения 
byte waitbyte_RX = 1;      // задержка, мс для успевания заполнения буфера RX (подрегулировать в зависимости от уровня жизнидеятельности на Марсе)
uint32_t timerdelay = 0;   // таймер ожидания байт (для успевания заполнения буфера УАРТ)
bool Delay = 0;            // таймер ожидания байт (для успевания заполнения буфера УАРТ)
#define TIMER_DELAY Delay = 0; timerdelay = curmillis  // включение этого таймера

uint32_t prevRESETheader=0; // таймер сброса заголовка если в момент приёма сообщения данные оборвались
bool RESETheader_timer = 0; // таймер сброса заголовка если в момент приёма сообщения данные оборвались

// команды для котлов ЭВО
byte StartByte = 0x20;
byte HEATER_BEGIN[]         {0x51, 0x0A};
byte HEATER_START[]         {StartByte, 0x3B};
byte HEATER_PRESENCE[]      {0x44, StartByte, 0x00};
byte HEATER_STOP[]          {0x10};
byte HEATER_STATUS_VEVO[]   {0x50, 0x05};
byte HEATER_STATUS_EVO[]    {0x50, 0x30, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x1E, 0x32};
byte HEATER_DTC_REQUEST[]   {0x56, 0x01};
byte HEATER_DTC_ERASE[]     {0x56, 0x03};

// команды для котлов ТТС/TTE
byte START_SESSION[]        {0x81};
byte REQUEST_2A10101[]      {0x2A, 0x01, 0x01};
byte REQUEST_2A10102[]      {0x2A, 0x01, 0x02};
byte REQUEST_2A10105[]      {0x2A, 0x01, 0x05};
byte REQUEST_DTC[]          {0xA1};
byte START_TTC[]            {0x31, 0x22, 0xFF};
byte STOP_TTC[]             {0x31, 0x22, 0x00};


enum needAction_ {NO_ACTION, NEED_SMSZAPROS, NEED_SERVICEINFO, NEED_DTCCLEAR};// возможные действия, стоящие в очереди
byte needAction = NO_ACTION;                                                  // переменная действия, стоящего в очереди

enum ProtocolSTATUS_ {STATUSBUS, ANALOG};                   // возможные протоколы чтения статуса котла
enum ProtocolSTART_  {STARTBUS, IMPULSE, POTENCIAL};        // возможные протоколы запуска котла
enum Heater_         {TTC_E, VEVO, EVO, HYDRONIC};          // тип котла

byte  ProtocolSTATUS = STATUSBUS; 
byte  ProtocolSTART  = STARTBUS;
byte  Heater         = EVO;

bool noData  = 0;                               // флаг пришли ли данные от котла после запроса. 
byte w_bus_init = 0;                            //флаг проведена или нет инициализация шины w-bus (25мс LOW, 25мс HIGH для  ЭВО
                                                //                                            либо 300ms LOW, 50ms HIGH, 25ms LOW, 3025ms HIGH для TTC 
byte requiredmessage =  1;                      //флаг, что отправляем в данный момент поддержание старта, запрос параметров или запрос ошибок
byte StartMessageRepeat = 0;                    //количество отправленных сообщений на старт котла
byte StopMessageRepeat =  4;                    //количество отправленных сообщений на остановку котла

byte  TimeWebasto = 30;                         //время работы котла, = 30мин
uint32_t EndReportMillis = 0;                   //переменная для таймера отправки отчета об успешности запуска котла
uint32_t EndReportEngine = 0;                   //переменная для таймера отправки отчета об успешности запуска ДВС
uint32_t Prev_PeriodW_BusMessage = 0;           //переменная для таймера периодической отправки сообщений состояния котла в шину W-Bus 
uint32_t Prev_PeriodW_BusStartStop = 0;         //переменная для таймера периодической отправки сообщений старта/стопа котла в шину W-Bus 
uint32_t prevdelSMS = 0;                        //переменная для таймера периодического удаления СМС 
uint32_t prevVpit = 0;                          //переменная для таймера периодического измерения напряжения АКБ
uint32_t prevInitreset = 0;                     //переменная для таймера сброса инита шины
bool Initreset = 0;                             //переменная для таймера сброса инита шины
uint32_t timerInit = 0; bool timerInitflag = 0; //для таймера инита шины W-BUS
uint32_t prevNeedTimer = 0; bool NeedTimer = 0; //для таймера задержки функций SMSzapros() и ServiceINFO() на время обновления параметров по шине


uint32_t last_Flame = 0;                        //для таймера сброса флага пламени, если нет ответов от котла

//для таймера создания импульса GND - для протокола запуска котла импульсом GND 
uint32_t timer=0; bool timerenabled=false;
#define TIMEREXPIRED (curmillis-timer)>800

//для таймера  - старт двигателя - импульс +5В на транзистор, в итоге минусовой импульс 1.5 сек на вход событий сигналки для запуска ДВС)
uint32_t  timerStartEng=0; bool timerenabledStartEng=false;
#define TIMEREXPIRED_StartEng (millis()-timerStartEng)>1500

//для таймера  - старт котла по W-BUS )
uint32_t timerStart_W_BUS=0; bool timerenabledStart_W_BUS=false;
#define TIMEREXPIRED_Start_W_BUS (curmillis-timerStart_W_BUS)> (uint32_t)TimeWebasto * 60000UL



//---------------------------------Основные переменные--------------------------------------------------------------------------------  

bool webasto = 0;             // флаг команды на работу Webasto. 0 - котел выключен, 1 - котел включен
bool startWebasto_OK = 0;     // флаг успешного запуска котла
bool report = false;          // флаг нужности отправки отчета false - не нужно отправлять, true - нужно отправлять
bool reportEngine = false;    // флаг нужности отправки отчета false - не нужно отправлять, true - нужно отправлять
bool engine =0;               // флаг работает ли ДВС или нет
bool ignition=0;              // флаг включено ли зажигание или нет
bool ohrana=0;                // флаг включена ли охрана или нет
bool trevoga=0;               // флаг включена ли тревога или нет
bool alarmSMS = 0;            // флаг отправлена ли смс о тревоге или нет

bool waterpump = 0;           // флаг работы циркуляционного насоса
bool plug      = 0;           // флаг работы штифта накаливания
bool airfan    = 0;           // флаг работы нагнетателя воздуха
bool fuelpump  = 0;           // флаг работы топливного насоса
bool blowerfan = 0;           // флаг работы вентилятора печки автомобиля
byte DTC[7] ={0};             // коды неисправностей котла



//---------------------------СТАРТОВЫЙ ЦИКЛ--------------------------------------------------------------------------------------------

void setup() 
{


delay (3500);


test.NO(); 
test.pullUp();
test.duration_bounce       (  50);
test.duration_click_Db     ( 250);
test.duration_inactivity_Up(5000);
test.duration_inactivity_Dn(1000);
test.duration_press        ( 500);
test.button(StartButtonpin);            // в скобках пин тактовой кнопки вкл/выкл котла (программный номер у неё будет 0)
 
pinMode (DopOn,   INPUT_PULLUP); 
pinMode (DopOff,  INPUT_PULLUP); 
pinMode (Sost,    INPUT_PULLUP); 
pinMode (Ohrana,  INPUT_PULLUP); 
pinMode (Trevoga, INPUT_PULLUP); 
pinMode (IGN,     INPUT_PULLUP); 
pinMode (Eng,     INPUT_PULLUP); 
  
pinMode (OutWebasto_12V,     OUTPUT);  digitalWrite (OutWebasto_12V,      LOW);
pinMode (StartEng,           OUTPUT);  digitalWrite (StartEng,            LOW);
pinMode (13,                 OUTPUT);  digitalWrite (13,                  LOW);
pinMode (StatusWebastoLED,   OUTPUT);  digitalWrite (StatusWebastoLED,    LOW);
pinMode (OutWebasto_GndImp,  OUTPUT);  digitalWrite (OutWebasto_GndImp,   HIGH);
pinMode (DTR,                OUTPUT);  digitalWrite (DTR,                 HIGH);  // делаем высокий, а низкий уровень будет для пробуждения GSM из "спячки"
pinMode (ResetGSM,           OUTPUT);  digitalWrite (ResetGSM,        !RelayON);  // реле ресет на данный момент делаем "неактивно"


   SIM800.begin(19200);           // сериал соединение для gsm модуля
   delay(100);
   NastroykaGSM ();


TimeWebasto =    EEPROM.read(TimeWebasto_cell);
ProtocolSTART  = EEPROM.read(ProtocolSTART_cell);
ProtocolSTATUS = EEPROM.read(ProtocolSTATUS_cell);
ResetNumber =    EEPROM.read(ResetNumber_cell);
StartByte =      EEPROM.read(StartByte_cell);
Heater =         EEPROM.read(Heater_cell);
delta  =         EEPROM.read(delta_cell);
for (int i=0; i<11; i++) TelNumber[1][i] = EEPROM.read (i+TelNumber1_cell);
for (int i=0; i<11; i++) TelNumber[2][i] = EEPROM.read (i+TelNumber2_cell);

// ниже читаем из еепром адреса датчиков температуры даллас 
for (byte i = 0; i<size_arrayTemp; i++) {
    for (byte k=0; k<9; k++) DS18B20 [i][k] = EEPROM.read(DallasAddr_cell+i*10+k);
    }



        if (Heater == EVO || Heater == VEVO) K_LINE.begin(2400, SERIAL_8E1);
   else if (Heater == TTC_E) K_LINE.begin(10400);


for (byte i=0; i<20; i++) {digitalWrite (13, !digitalRead(13)); delay (80);}
digitalWrite (13,0);
}



//------------------------------------------ЛУП-----------------------------------------------------------------------------------


void loop() {
curmillis = millis();
test.read();

digitalWrite (StatusWebastoLED, webasto);
//digitalWrite (13, startWebasto_OK);
//digitalWrite (13, webasto);


//если нажали тактовую кнопку меняем состояние котла на противоположное 
if (test.event_press_short (StartButton)) {
  if (!webasto) {StartWebasto(); report = false;}
  else StopWebasto();
    }

if (ProtocolSTATUS==ANALOG) {if (Temper(VyhlopC) - Temper(UlicaC) > delta) startWebasto_OK = 1;
                             else startWebasto_OK = 0;}

if (ProtocolSTART==IMPULSE) webasto = !digitalRead (Sost);

Heater_BUS();

//ниже для таймера старта котла по шине и аналогу 
 
  if (timerenabledStart_W_BUS && TIMEREXPIRED_Start_W_BUS) StopWebasto();

//ниже для таймера создания импульса на старт ДВС 

if (timerenabledStartEng && TIMEREXPIRED_StartEng) {digitalWrite (StartEng, LOW); timerenabledStartEng=false;}
    
 engine =  !digitalRead (Eng);
 ignition= !digitalRead (IGN); 
 ohrana=   !digitalRead (Ohrana);  
 trevoga=  !digitalRead (Trevoga);
  
if (webasto && report) timerReport ();
if (reportEngine) timerReportEngine ();
if (!ohrana) alarmSMS = false;


   if (trevoga && !alarmSMS) AlarmSMS ();
   if (gsmOK)readSMS();
   Reset_gsm();
   delSMS();


WebastoOprosImpulse ();
izmereniya();

}


//-----------------------------------------------------------конец луп-------------------------------------------------------------



void izmereniya() { 

if (millis()-prevVpit>7000){

//измерение напряжения борт сети
if (ProtocolSTATUS==ANALOG){
   volt = analogRead(Voltmeter_pin);                      
   vout = (volt * 4.13) / 1024;             
   Vpit = vout / (9700.0/(98930.0+9700.0));  // По формуле Vpit = vout / (R2/(R1+R2)) 
   if (Vpit<0.09)  Vpit=0.0;                  // Округление до нуля 
}  

// ниже измерение датчиков даллас
static bool n=0;        // флаг работы: запрос температуры или её чтение
n=!n;
if (n) {ds.reset();     // сброс шины
        ds.write(0xCC); // обращение ко всем датчикам
        ds.write(0x44); // начать преобразование (без паразитного питания)  
       }
else   {
  for (byte i=0; i<size_arrayTemp; i++){  
    int Temper_ = 20; byte buff[9];
    ds.reset();
    ds.select(DS18B20[i]);
    ds.write(0xBE); // чтение регистров датчиков
    for (byte j=0; j<9; j++) buff[j]=ds.read(); // читаем все 9 байт от датчика
    ds.reset();
    if (OneWire::crc8(buff, 8) == buff[8]){     // если контрольная сумма совпадает 
          Temper_ = buff[0]|(buff[1]<<8);       // читаем температуру из первых двух байт (остальные были нужны только для проверки CRC)
          Temper_ = Temper_ / 16;
          if (Temper_<150 && Temper_>-55) DS18B20[i][9] = Temper_;
}
else DS18B20[i][9] = -101;                     // если контрольная сумма не совпала, пусть t будет -101 градус. 
}}


prevVpit=millis();
}}



int8_t Temper (const byte &addressTemp) {for(byte j=0; j<size_arrayTemp; j++){if(DS18B20[j][8]==addressTemp)return(int8_t)DS18B20[j][9];} return-99;}



void WebastoOprosImpulse (){

// опрос допканалов от сигнализации включения/ выключение котла и таймер импульса старт/стоп котла 
  
  if (timerenabled) {if (TIMEREXPIRED) {digitalWrite (OutWebasto_GndImp, HIGH); timerenabled=false;}}
  else  {if (!digitalRead (DopOn)  && !webasto) {StartWebasto(); KTOreport = 1;}
         if (!digitalRead (DopOff) && webasto) StopWebasto();
         }}


// цикл таймера отправки отчета об успешности запуска котла (отчёт через 6 мин после старта)
void timerReport () {
   if(millis() - EndReportMillis > 360000UL) 
   {EndReportMillis = millis(); report = false; SMSzapros();  }} 

// цикл таймера отправки отчета об успешности запуска ДВС  (отчёт через 60сек после старта)                       
void timerReportEngine () {
   if(millis() - EndReportEngine > 90000ul) 
   {EndReportEngine = millis(); reportEngine = false; SMSzapros_();}} 





   void NastroykaGSM () {
  digitalWrite (DTR, LOW);      // выводим из спячки GSM модуль
    delay (150);
  SIM800.println(F("AT"));                    //просто AT для разогреву
    delay(250);
  SIM800.println(F("AT+CMGF=1"));             //устанавливает текстовый режим смс-сообщения
    delay(250);
  SIM800.println(F("AT+IFC=0, 0"));           //отключает программный контроль потоком передачи данных
    delay(250);
  SIM800.println(F("AT+GSMBUSY=1"));          //запрет всех входящих звонков
    delay(250);
  SIM800.println(F("AT+CNMI=1,2,2,1,0"));     //включает оповещение о новых сообщениях
    delay(250);
  SIM800.println(F("AT+CMGDA=\"DEL ALL\""));  // удаляем все смс, ки
   delay(1500);
  SIM800.println(F("AT+CSCLK=1"));            //включает энергосберегающий режим 
  delay(150);
  digitalWrite (DTR, HIGH);     // вводим в спячку GSM модуль высоким уровнем на пине DTR
  
}

void startSMS(byte stat) //__________________Цикл подготовки модуля к отправке СМС-сообщений по первому номеру
{
    if (stat==0) stat = KTOreport;
     digitalWrite (DTR, LOW); // выводим из спячки GSM модуль
         delay (150);
     SIM800.print(F("AT+CMGF=1\r"));
         delay(200);
     SIM800.print(F("AT+CMGS=\"")); SIM800.print(TelNumber[stat]); SIM800.println("\""); 
         delay(200);
}



void EndSMS ()
{
   SIM800.println((char)26);                       // Команда отправки СМС
   delay(1500);
   digitalWrite (DTR, HIGH); // вводим в спячку SIM800 модуль 
   
}

void delSMS ()
{
if (millis() - prevdelSMS > 7200000ul){  //раз в 2 часа 
 digitalWrite (DTR, LOW); // выводим из спячки SIM800 модуль
    delay (150);
 SIM800.print(F("AT+CMGDA=\"DEL ALL\"\r")); // удаляем все смс, ки
   delay(1500);
 digitalWrite (DTR, HIGH); // вводим в спячку SIM800 модуль 
   delay (150);

  prevdelSMS = millis();}
}


void SMSzapros_ () {if (webasto)SMSzapros(); else {NeedTimer = 1; prevNeedTimer = curmillis; needAction = NEED_SMSZAPROS; w_bus_init = 1;}}

void readSMS() //_____Цикл чтения входящих СМС-сообщений______________     
{
    if (!SIM800.available()) return;
    static bool SaveNumber2 = 0;      // флаг когда необходима запись номера#2, он true
    char currSymb = SIM800.read();

    if ('\r' == currSymb)
       {
         if (isStringMessage!=0&&isStringMessage!=3) //если текущая строка - SMS-сообщение, отреагируем на него соответствующим образом
                {
if      (!currStr.compareTo("ZAPROS"))       {SMSzapros_();}             // Передача параметров по СМС
else if (!currStr.compareTo("ZAPROSTEL"))    {SMSzaprosTEL();}           // Передача номеров телефонов пользователей по СМС
else if (!currStr.compareTo("Service-info")) {if (webasto) ServiceINFO(); else {NeedTimer = 1; prevNeedTimer = curmillis; needAction = NEED_SERVICEINFO;w_bus_init = 1;}}            // Передача сервисной информации  по СМС
else if (!currStr.compareTo("GSMResets-0"))  {ResetNumber=0; EEPROM.write (ResetNumber_cell, ResetNumber); ServiceINFO();}     //сброс счетчика ресетов GSM модуля
else if (!currStr.compareTo("Version"))      {startSMS(isStringMessage);  SIM800.println (ver); EndSMS ();}               //запрос версии ПО
else if (!currStr.compareTo("Erase DTC"))    {NeedTimer = 1; prevNeedTimer = curmillis; needAction = NEED_DTCCLEAR; if (w_bus_init == 0) w_bus_init = 1;}               //запрос на стриание ошибок

else if (!currStr.compareTo("Signal-level")) {digitalWrite (DTR, LOW);  delay (150); SIM800.println(F("AT+CSQ")); digitalWrite (DTR, HIGH);}                // запрос уровня сигнала GSM
              
else if (!currStr.compareTo("Webasto-ON"))  { startSMS(isStringMessage); SIM800.println(F("Webasto ")); 
  
           if (!webasto)  {StartWebasto (); KTOreport = isStringMessage;}
           else SIM800.println(F("uzhe ")); SIM800.println (F("vkluchena")); EndSMS();}

                                                            
else if (!currStr.compareTo("Webasto-OFF"))   {startSMS(isStringMessage); SIM800.println(F("Webasto "));  
           if (webasto)StopWebasto ();  // если получили команду на выключение и вебаста в настоящий момент включена - выключаем
           else SIM800.println(F("uzhe "));  SIM800.println(F("otkluchena"));EndSMS();}          

// если получили команду на включение ДВС и он в настоящий момент выключен - включаем
else if (!currStr.compareTo("Engine-ON"))  {startSMS(isStringMessage); SIM800.println(F("Dvigatel "));  
           if (!engine)  { digitalWrite (StartEng, HIGH);  timerStartEng=millis(); timerenabledStartEng=true; reportEngine = true; EndReportEngine = timerStartEng; KTOreport = isStringMessage;} 
           else SIM800.println(F("uzhe ")); SIM800.println(F("start")); EndSMS();}
                                                                                 
else if (!currStr.compareTo("Engine-OFF"))   {startSMS(isStringMessage); SIM800.println(F("Dvigatel "));  
           if (engine){ digitalWrite (StartEng, HIGH);  timerStartEng=millis(); timerenabledStartEng=true; reportEngine = false;} // если получили команду на выключение ДВС и он в настоящий момент работает - выключаем
           else SIM800.println(F("uzhe ")); SIM800.println(F("ostanovlen")); EndSMS();}          
              
else if (!currStr.compareTo("Impulse"))   {if (!webasto) {ProtocolSTART = IMPULSE;  EEPROM.write(ProtocolSTART_cell,ProtocolSTART);     
                                            startSMS(isStringMessage); SIM800.println(F("zapusk GND_impulse")); EndSMS();}}

else if (!currStr.compareTo("Startbus"))  {if (!webasto) {ProtocolSTART = STARTBUS; EEPROM.write(ProtocolSTART_cell,ProtocolSTART);  webasto = 0;  
                                            startSMS(isStringMessage); SIM800.println(F("zapusk BUS")); EndSMS();}}

else if (!currStr.compareTo("Potencial")) {if (!webasto) {ProtocolSTART = POTENCIAL; EEPROM.write(ProtocolSTART_cell,ProtocolSTART);   
                                            startSMS(isStringMessage); SIM800.println(F("zapusk +12V Potencial")); EndSMS();}}

else if (!currStr.compareTo("DallasAddr")) {startSMS(isStringMessage); SMSDallasAddr(); EndSMS();}

else if (currStr.endsWith("Status"))   {if (!webasto) {byte st = currStr.toInt(); if (st >= STATUSBUS && st<=ANALOG )ProtocolSTATUS = st; EEPROM.write(ProtocolSTATUS_cell,ProtocolSTATUS);   
                                            startSMS(isStringMessage); SIM800.print (F("Status: "));
                                                                             if (ProtocolSTATUS == 0)SIM800.println(F("BUS")); 
                                                                        else if (ProtocolSTATUS == 1)SIM800.println(F("Analog"));
                                                                        EndSMS();}}    


else if (currStr.endsWith("HeaterType")) {if (!webasto) {byte st = currStr.toInt(); if (st >= TTC_E && st<=HYDRONIC) Heater = st; EEPROM.write(Heater_cell,Heater);   
                                            startSMS(isStringMessage); SIM800.print (F("Heater: "));
                                                                             if (Heater == 0)SIM800.println(F("TTC_E")), K_LINE.end(),  K_LINE.begin(10400);
                                                                        else if (Heater == 1)SIM800.println(F("VEVO")),  K_LINE.end(),  K_LINE.begin(2400, SERIAL_8E1);
                                                                        else if (Heater == 2)SIM800.println(F("EVO")),   K_LINE.end(),  K_LINE.begin(2400, SERIAL_8E1);
                                                                        else if (Heater == 3)SIM800.println(F("HYDRONIC"));
                                                                             
                                                                        EndSMS();}}      




else if (currStr.endsWith("ADDR")) {if (!webasto) { startSMS(isStringMessage); byte savadr = ConvertAddr(); 
                                                    if (savadr>=0 && savadr<=3) {SIM800.print(F("address ")); TempName(savadr); SIM800.println (F(" saved OK!")); 
                                                    SMSDallasAddr();
                                                                                } 
                                                    else SIM800.println(F("address is incorrect!"));
                                                    
                                                                          EndSMS(); }}      
                                                                                                                                                
                                                                                                                                              
else if (currStr.endsWith("Delta"))   {if (!webasto) {delta = currStr.toInt(); //
               EEPROM.write(delta_cell, delta);  startSMS(isStringMessage);
               SIM800.print(F("DeltaT: ")); SIM800.print(delta); SIM800.print(F("*C")); EndSMS();}}
                                                                                                                                            

               
else if (currStr.endsWith("min"))   {if (!webasto) {TimeWebasto = currStr.toInt(); // для задания время цикла работы отправить сообщение вида "25 min", где 25 время работы в мин
               if (TimeWebasto>59)  TimeWebasto = 59;
               if (TimeWebasto<=15) TimeWebasto = 15;
               EEPROM.write(TimeWebasto_cell,TimeWebasto);
               startSMS(isStringMessage); SIM800.print(F("Webasto time: ")); SIM800.print(TimeWebasto); SIM800.print(F("min")); EndSMS();}}
               
else if (currStr.endsWith("StartByte")) {byte Z =currStr.toInt(); if (Z>=0x14 && Z<=0x17) StartByte= Z+12;
               startSMS(isStringMessage); SIM800.print(F("StartByte: ")); SIM800.print(StartByte, HEX); SIM800.print(F("h")); EndSMS();}

else if (!currStr.compareTo("ResetNumbers"))   {if (isStringMessage == 1) {startSMS(isStringMessage); SIM800.println(F("Phone numbers are erased")); EndSMS(); 
                                                                     
             TelNumber[1] = "00000000000"; TelNumber[2] = "00000000000"; for (int i=0; i<11; i++) {EEPROM.write (i+TelNumber1_cell,  TelNumber[1][i]); EEPROM.write (i+TelNumber2_cell,  TelNumber[2][i]); }}}

else if (!currStr.compareTo("WriteNumber2")&& isStringMessage == 1)   { 
                SaveNumber2 = 1; startSMS(isStringMessage); SIM800.println(F("Otpravte lyuboye SMS s nomera#2 dlya sohraneniya nomera")); EndSMS();} 

                                                                        

                                                     
else if (!currStr.compareTo("Balance"))    SMSbalance();
            isStringMessage = 0;
                }
              
              
else if (isStringMessage==3){ if (!currStr.compareTo("WriteNumber1"))   { TelNumber[1] = TelNumber[3]; for (int i=0; i<11; i++) {EEPROM.write (i+TelNumber1_cell, TelNumber[3][i]);}
              startSMS(1); SIM800.println(F("Tel Number#1 is saving in memory"));  SIM800.print("Tel#1: ");  SIM800.println (TelNumber[1]); EndSMS();
              } 
                                             else if (!currStr.compareTo("ZAPROS"))   { SMSzapros();}   
                                             else if (!currStr.compareTo("ZAPROSTEL"))   { SMSzaprosTEL();}               // Передача номеров телефонов пользователей по СМС            
               isStringMessage = 0;
              
              }           



                
else if (isStringMessage==0) {  if (TelNumber[1]!="00000000000" && !SaveNumber2 && TelNumber[1]!="яяяяяяяяяяя"){
         
                     if (currStr.startsWith("+CMT: \""+TelNumber[1])) { isStringMessage = 1; KTOzapros = 1; }   
                else if (currStr.startsWith("+CMT: \""+TelNumber[2])) { isStringMessage = 2; KTOzapros = 2; }   
                else if (currStr.startsWith("+CUSD: 0,"))  //если текущая строка начинается с "+CUSD",то следующая строка является запросом баланса
                  {
                  startSMS(KTOzapros);
                  SIM800.print (currStr);
                  EndSMS();
                  }

                else if (currStr.startsWith("+CSQ:")) //если текущая строка начинается с "+CSQ",то значит был запрос на уровень сигнала GSM, отправим ответ запрашивающему
                  {
                  startSMS(KTOzapros);
                  SIM800.print (currStr);
                  EndSMS();
                  }
                                                }

                else if    (currStr.startsWith("+CMT:") && !SaveNumber2) { isStringMessage = 3; for (int i =0; i<11; i++) {TelNumber[3][i]=currStr[i+7];}}
                else if    (currStr.startsWith("+CMT:") && SaveNumber2) { for (int i =0; i<11; i++) {TelNumber[3][i]=currStr[i+7];} TelNumber[2] = TelNumber[3]; for (int i=0; i<11; i++) {EEPROM.write (i+TelNumber2_cell, TelNumber[3][i]);}
              startSMS(2); SIM800.println(F("Vash nomer sochranyon kak Number#2 v pamyati!")); 
              SIM800.print(F("Tel#1: ")); SIM800.println(TelNumber[1]); SIM800.print(F("Tel#2: "));  SIM800.println (TelNumber[2]); EndSMS(); SaveNumber2 = 0; } 
              
              } 
               
        currStr = "";
      } 
 
    else if ('\n' != currSymb && currSymb!=0x13 && currSymb!=0x11)  currStr += String(currSymb);
}




byte ConvertAddr() {
  
  byte addrbuf[9];
byte Cs=0;
for (byte i = 0; i<9; i++) {
    char str[]="  ";
    for (byte k = 0; k<2; k++) str[k] = currStr[3*i+k];

 addrbuf[i] = strtol(str,NULL,HEX);
      if (i<7) Cs+= addrbuf[i] = strtol(str,NULL,HEX);
 
  }
if (OneWire::crc8(addrbuf, 7) == addrbuf[7] && addrbuf[8]>=0 && addrbuf[8]<=3) { 

for (byte i = 0; i<size_arrayTemp; i++) {
  if (addrbuf[8]==DS18B20[i][8]) {for (byte k=0; k<9; k++) DS18B20 [i][k] = addrbuf[k], EEPROM.write (DallasAddr_cell+addrbuf[8]*10+k, addrbuf[k]);}
                                        }

return addrbuf[8];
}
else return 20; 
  }

void SMSDallasAddr(){
 
SIM800.println (F("Dallas Addresses:"));

for (byte i = 0; i<size_arrayTemp; i++) {
   TempName(DS18B20[i][8]); SIM800.println(); 
   for (byte k = 0; k<8; k++) {if (DS18B20[i][k]<=0x0F)SIM800.print(F("0")); SIM800.print(DS18B20[i][k],HEX); SIM800.print(F(" "));}
  SIM800.println(); 
  }

   
                              
  }



void SMSzaprosTEL(){
  startSMS(isStringMessage);
  PrintNumbers (); 
  EndSMS();                                 
  }


void SMSbalance() {
digitalWrite (DTR, LOW); // выводим из спячки SIM800 модуль
      delay (150);
SIM800.print(F("AT+CMGF=1\r"));
      delay(200);
SIM800.println (F("AT+CUSD=1,\"#100#\""));    // команда на замену на транслит *111*6*2# у МТС 
      delay(1500);  
digitalWrite (DTR, HIGH); // вводим в спячку SIM800 модуль 
      delay (150);  
                             
     
}


void AlarmSMS() {for (byte i = 0; i<2; i++) {startSMS(i+1); SIM800.println (F("Vnimanie!!! Trevoga!!! Sirena Vkl!")); EndSMS();} alarmSMS = true;}
 


void PrintNumbers () {for (byte i=0; i<2; i++) {SIM800.print(F("Tel#")); SIM800.print (i+1); SIM800.print(F(" ")); SIM800.println(TelNumber[i+1]);}}




void TempName (const byte &_address_) {     if (_address_== VyhlopC) SIM800.print(F("Vyhlop:  "));
                                       else if (_address_== EngineC) SIM800.print(F("Engine:  "));
                                       else if (_address_== UlicaC)  SIM800.print(F("Ulica:     "));
                                       else if (_address_== SalonC)  SIM800.print(F("Salon:    "));
                                       }

void SMSzapros()

{

  startSMS(isStringMessage);
  if (isStringMessage == 3){
 
 SIM800.println (F("Tel.number#1 not has been save in memory"));
 SIM800.println (F("For save Tel#1 send SMS command \"WriteNumber1\""));
 PrintNumbers ();
  }
  

  
  
  else {
  
SIM800.print (F("Webasto ")); on_off (webasto);
        if (webasto) { 
           SIM800.print (F("StartWebasto "));
           if (startWebasto_OK) SIM800.println (F("OK"));
           else SIM800.println (F("FAIL"));}
SIM800.print (F("Engine    "));  on_off (engine);
SIM800.print (F("IGN        ")); on_off (ignition);
SIM800.print (F("Ohrana  "));    on_off (ohrana);
     if (trevoga)  SIM800.println (F("Vnimanie!!! Trevoga!!! Sirena Vkl!"));
     
  SIM800.print(F("Battery: "));      if ((needAction>0 && !noData) || needAction == 0 || ProtocolSTATUS == ANALOG) {SIM800.print (Vpit,1); SIM800.println(F(" V"));}
                                else if (needAction>0 && noData && ProtocolSTATUS != ANALOG) SIM800.println(F(" No Data"));
  
  SIM800.println(F("Temperatures:"));
  if (ProtocolSTATUS != ANALOG){
  SIM800.print(F("Heater:  ")); if ((needAction>0 && !noData) || needAction == 0) {SIM800.print (HeaterC);  grad ();}
                                else if (needAction>0 && noData) SIM800.println(F(" No Data"));}
 
 // ниже распечатаем все температуры   
    for (byte i = 0; i<size_arrayTemp; i++) {
      if (DS18B20[i][8]==VyhlopC && ProtocolSTATUS != ANALOG) {}
      else {TempName(DS18B20[i][8]); SIM800.print (Temper(DS18B20[i][8])); grad ();}}
  

  if (ProtocolSTATUS == STATUSBUS){
  SIM800.print(F("Errors:   ")); if ((needAction>0 && !noData) || needAction == 0) SIM800.println (DTC[0]);
                                else if (needAction>0 && noData) SIM800.println(F(" No Data"));}
  
  
 
  }  
   EndSMS();    
                          
}

void on_off (const bool &stat) {if (stat) SIM800.println (F("ON")); else SIM800.println (F("OFF")); }
void grad () {SIM800.println (F("*C")); }





void ServiceINFO(){
  
       startSMS(isStringMessage);
  SIM800.print(F("Heater:  ")); 
       if (Heater==TTC_E)     SIM800.println(F("TTC/E"));
  else if (Heater==VEVO)      SIM800.println(F("VEVO"));
  else if (Heater==EVO)       SIM800.println(F("EVO"));
  else if (Heater==HYDRONIC)  SIM800.println(F("HYDRONIC"));
  SIM800.print(F("Start:    "));
       if (ProtocolSTART==IMPULSE)   SIM800.println(F("GND Imp"));
  else if (ProtocolSTART==STARTBUS)  {SIM800.print(F("BUS"));
             if (Heater== VEVO || Heater== EVO) {SIM800.print(F(" 0x")); SIM800.println (StartByte, HEX);}
             else SIM800.println();}
  else if (ProtocolSTART==POTENCIAL) SIM800.println(F("Potencial+12V"));
  
  SIM800.print(F("Status:  "));
       if (ProtocolSTATUS==ANALOG)    SIM800.println(F("ANALOG"));
  else if (ProtocolSTATUS==STATUSBUS) SIM800.println(F("BUS"));
  
   
  if (ProtocolSTART!=IMPULSE) {SIM800.print(F("Webasto Time: ")); SIM800.print (TimeWebasto); SIM800.println(F("min"));}
  SIM800.print(F("SIM800 Resets: ")); SIM800.println (ResetNumber); 

  if (ProtocolSTATUS==ANALOG) {SIM800.print(F("DeltaT:  ")); SIM800.print(delta);SIM800.println(F("*C"));}

  if (ProtocolSTATUS==STATUSBUS){
    if (!noData) {
    SIM800.print(F("   BurnFAN       ")); on_off (airfan);
    SIM800.print(F("   WaterPUMP ")); on_off (waterpump);
    SIM800.print(F("   PLUG            ")); on_off (plug);
    SIM800.print(F("   FuelPUMP    ")); on_off (fuelpump);
    SIM800.print(F("   Blower          ")); on_off (blowerfan);
    
   SIM800.print (F("Errors:  ")); SIM800.println (DTC[0]);
  if (DTC[0] >0) for (byte i=0; i<DTC[0]; i++) {
  if (DTC[i+1]<=0x0F) SIM800.print(F("0"));
     SIM800.print (DTC[i+1], HEX); 
     if (bitRead(DTC[6], i+1)) SIM800.println (F(" Active")); 
     else SIM800.println (F(" Passive"));      }
                             }
 else SIM800.println(F("Heater not answer. No Data"));}
   EndSMS();    
  
  }

void StartWebasto()
{
 if (ProtocolSTART==IMPULSE){
  
  digitalWrite (OutWebasto_GndImp, LOW); 
  timer=curmillis; 
  timerenabled=true;}

 else {
  StartMessageRepeat = 0;
  webasto = 1; digitalWrite (OutWebasto_12V, HIGH);
  timerStart_W_BUS=millis();
  timerenabledStart_W_BUS = true;}

  report = true; EndReportMillis = millis();
  w_bus_init = NEED;
}

void StopWebasto()
{
 if (ProtocolSTART==IMPULSE){ digitalWrite (OutWebasto_GndImp, LOW); 
  timer=curmillis; 
  timerenabled=true;}

 else {
  StopMessageRepeat = 0;
  webasto = 0; digitalWrite (OutWebasto_12V, LOW);
  timerenabledStart_W_BUS = false;}
   report = false;
   
   
}



void Heater_BUS (){
  
if      (Heater == EVO || Heater == VEVO){
if (webasto) {
    if (StartMessageRepeat<4 && (millis()-Prev_PeriodW_BusStartStop>800) && w_bus_init >= 9){
  sendMessage (HEATER_START, sizeof(HEATER_START)); 
  StartMessageRepeat++; 
  Prev_PeriodW_BusStartStop = millis();
  
    }
  if (StartMessageRepeat>=4){ if (millis()-Prev_PeriodW_BusMessage>4000)  {
    
         if (requiredmessage==1) sendMessage (HEATER_PRESENCE, sizeof(HEATER_PRESENCE));  
    else if (requiredmessage==2) {if (Heater == EVO) sendMessage (HEATER_STATUS_EVO,  sizeof(HEATER_STATUS_EVO));
                                  if (Heater == VEVO)sendMessage (HEATER_STATUS_VEVO, sizeof(HEATER_STATUS_VEVO));}
    else if (requiredmessage==3) sendMessage (HEATER_DTC_REQUEST, sizeof(HEATER_DTC_REQUEST));  
requiredmessage++; if (requiredmessage > 3) requiredmessage = 1;
StopMessageRepeat = 0;
    
    Prev_PeriodW_BusMessage = millis();
    }}}





else if (StopMessageRepeat<4 && (millis()-Prev_PeriodW_BusStartStop>800)){
  sendMessage (HEATER_STOP, sizeof(HEATER_STOP));
StopMessageRepeat++; 
StartMessageRepeat = 0;
   Prev_PeriodW_BusStartStop = millis();
  
  
  }


if (!timerInitflag && w_bus_init==NEED) {K_LINE.end(); pinMode (TX, OUTPUT); digitalWrite(TX, 0); timerInit = millis(); timerInitflag = 1;}
if ( timerInitflag && (millis() - timerInit>24) && w_bus_init==NEED) {timerInit = millis(); digitalWrite(TX, 1); w_bus_init=2; }
if ( timerInitflag && (millis() - timerInit>24) && w_bus_init==2) {K_LINE.begin (2400,SERIAL_8E1 );timerInitflag = 0; w_bus_init=9; 
                                                                   if (needAction>0) sendMessage (HEATER_BEGIN, sizeof(HEATER_BEGIN));  }


if (K_LINE.available()){
    

 // первый старт байт
 if (header == 0 && Delay){TIMER_DELAY ; buf[0]=K_LINE.read();  
         if (buf[0]==0x4F || buf[0]==0x44){header = 1; RESETheader_timer=1; prevRESETheader = curmillis; }
         else {header = 0; RESETheader_timer=0;}
         }                  

 // длина сообщения
 if (header == 1 && Delay){TIMER_DELAY ; buf[1]=K_LINE.read(); message_size = buf[1]; if (message_size > bufsize) message_size = bufsize;  header = 4;j=2;n=2;checksum = 0;} 

 // пишем тело сообщения 
 if (header == 4 && Delay && j< message_size+n) {
 buf[j] = K_LINE.read();
 
 if (j<message_size+n-1) checksum^= buf[j]; // подсчёт КС
 
 if (j==message_size+n-1) header = 5; 
 TIMER_DELAY ; j++;} 

 } // end of K_LINE.available()

 // сообщение приняли, действуем
 if (header == 5) {TIMER_DELAY ;  
   
for(byte i = 0; i<n; i++) checksum^=buf[i]; // прибавляем к контрольной сумме старт байты

 // если контрольная сумма верна: 
if ( checksum == buf[message_size+n-1]) {
  
if (Heater == EVO){
    
     if (buf[2]==0xD0 && buf[3]==0x30)                          {    // если получили сообщение с текущими данными
               
                 if  (buf[4] ==0x0A) { 
                          airfan    = (bool)buf[5];                  // получаем флаг работы нагнетателя воздуха
                          plug      = (buf[5] & 0x02)>>1;            // получаем флаг работы штифта накаливания
                          fuelpump  = (buf[5] & 0x04)>>2;            // получаем флаг работы топливного насоса
                          waterpump = (buf[5] & 0x08)>>3;            // получаем флаг работы циркуляционного насоса
                          blowerfan = (buf[6] & 0x10)>>4;            // получаем флаг работы вентилятора печки автомобиля
                  
                                     }
                   
                 if  (buf[6] ==0x0C)  HeaterC = buf[7]-50;           // получаем температуру антифриза в котле 
                 if  (buf[8]==0x0E) {Vpit = (float)(buf[9]<<8|buf[10])/1000.0;}                 // получаем напряжение борт сети
                 if  (buf[11]==0x10) {startWebasto_OK = (bool)buf[12]; last_Flame = curmillis;} // проверяем наличие пламени                                                
                 
                 if (needAction>0 && needAction<NEED_DTCCLEAR) {w_bus_init = 12; sendMessage (HEATER_DTC_REQUEST, sizeof(HEATER_DTC_REQUEST));}
                                                                }

     if (buf[0]==0x44 && buf[2]==0xC4 && buf[3]==0x00) {w_bus_init = 1; delay (500); K_LINE.flush();}             // если получили от котла сбой инита, делаем переинит 
     
     if (buf[2]==0xD6 && buf[3]==0x01) {if (needAction>0 && needAction<NEED_DTCCLEAR) w_bus_init = 13;
      for (byte h = 0; h< sizeof(DTC); h++) DTC[h]=0;
      DTC[0] = buf[4];
      for (byte h = 0; h< buf[4]; h++) {DTC[h+1]=buf[h*3+5]; bitWrite (DTC[6], h+1,  (buf[h*3+6] & 0x02)>>1);}
            }  

     if (buf[2]==0xD6 && buf[3]==0x03)  {startSMS (KTOzapros); SIM800.println (F("DTCs are erased!")); EndSMS(); needAction=0; w_bus_init = 9; NeedTimer = 0;  }                   
     
     if (buf[2]==0xD1 && buf[3]==0x0A)  {w_bus_init = 10;   }// если получили ответ на сообщение старта коммуникации                    
                                                                
                  }

if (Heater == VEVO){
     if (buf[2]==0xD0 && buf[3]==0x05) {startWebasto_OK = buf[7]; last_Flame = millis();}       // проверяем наличие пламени у VEVO 
                  }
  
  
                                        }   

// если контрольная сумма не совпала: 

//else K_LINE.println("CRC fail!!!" );
  
message_size = 0; header=0; RESETheader_timer=0; j=2; checksum = 0;
}




}// end EVO VEVO


else if (Heater == TTC_E){



  
if (!timerInitflag && w_bus_init==NEED) {K_LINE.end(); pinMode (TX, OUTPUT); digitalWrite(TX, 0); timerInit = millis(); timerInitflag = 1;}
if ( timerInitflag && (millis() - timerInit>299)  && w_bus_init==NEED) {timerInit = millis(); digitalWrite(TX, 1); w_bus_init=2; }
if ( timerInitflag && (millis() - timerInit>49)   && w_bus_init==2) {timerInit = millis(); digitalWrite(TX, 0); w_bus_init=3; }
if ( timerInitflag && (millis() - timerInit>24)   && w_bus_init==3) {timerInit = millis(); digitalWrite(TX, 1); w_bus_init=4; }
if ( timerInitflag && (millis() - timerInit>3024) && w_bus_init==4) {K_LINE.begin (10400); timerInitflag = 0; w_bus_init=9;  sendMessage (START_SESSION, sizeof(START_SESSION));}

if (K_LINE.available()){
    

 // первый старт байт
 if (header == 0 && Delay){TIMER_DELAY ; buf[0]=K_LINE.read();  
         if (!bitRead (buf[0],6) && bitRead (buf[0],7)){header = 1; RESETheader_timer=1; prevRESETheader = curmillis; }
         
         }                  

 // второй старт байт
 if (header == 1 && Delay){TIMER_DELAY ; buf[1]=K_LINE.read(); if (buf[1]==0xF1){ header = 2;} else {header = 0; RESETheader_timer=0;}} 

 // третий старт байт
 if (header == 2 && Delay){ 
  TIMER_DELAY ;
  buf[2]=K_LINE.read(); 
  if (buf[2]==0x51){ message_size = buf[0]; 
  if (buf[0] !=0x80) {header = 4;  message_size&=~0x80; j=3; n=3;}
  else {header = 3; j=4;n=4;}
  if (message_size > bufsize) message_size = bufsize;  checksum = 0;} else {header = 0; RESETheader_timer=0; }
  
                          }  
// если размер сообщения указан в дополнительном байте (нулевой байт 0x80) читаем этот дополнительный байт:
if (header == 3 && Delay){
  TIMER_DELAY ;
  buf[3]=K_LINE.read(); 
  message_size = buf[3]; 
  if (message_size > bufsize) message_size = bufsize;  
  checksum = 0; header = 4;  
                         }

  // пишем тело сообщения 
 if (header == 4 && Delay && j< message_size+n+1) {
 buf[j] = K_LINE.read(); 
 if (j<message_size+n) checksum+= buf[j]; // подсчёт КС
 
 if (j==message_size+n) header = 5; 
 TIMER_DELAY ; j++;} 

 } // end of K_LINE.available()

 // сообщение приняли, действуем
 if (header == 5) {TIMER_DELAY ;  

for(byte i = 0; i<n; i++) checksum+=buf[i]; // прибавляем к контрольной сумме старт байты

//for (byte i=0; i<message_size+n+1; i++) {Serial.print (buf[i], HEX); Serial.print(" ");}

 // если контрольная сумма верна: 
if (buf[message_size+n] == checksum) {
  
//  if (buf[n]== 0xC1) Serial.println ("StartSession OK!!!");
  
  
  
  
  }   

// если контрольная сумма не совпала: 
//else Serial.println("CRC fail!!!" );
message_size = 0; header=0; RESETheader_timer=0; j=3; checksum = 0;
}

} // end TTC_E

// таймер ожидания байт (для успевания появления данных в буфере UART)
if (!Delay && curmillis - timerdelay > waitbyte_RX) Delay = 1; 

// таймер сброса заголовка если данные оборвались во время приёма заголовка
if (RESETheader_timer && curmillis - prevRESETheader > 500) {RESETheader_timer = 0; header = 0;}   

if (curmillis - last_Flame>20000 && ProtocolSTATUS==STATUSBUS) {startWebasto_OK=0; last_Flame = curmillis;}  // делаем статус "нет пламени" через 20 сек, если не получаем сообщения от котла

if (Initreset && curmillis - prevInitreset>17000) {Initreset = 0; w_bus_init = 0;}  // сброс инита, если прошло более 17 сек после отправки последнего сообщения


if (needAction>0 && needAction < NEED_DTCCLEAR && w_bus_init==10) {if (Heater == EVO) sendMessage (HEATER_STATUS_EVO,  sizeof(HEATER_STATUS_EVO));
                                     if (Heater == VEVO)sendMessage (HEATER_STATUS_VEVO, sizeof(HEATER_STATUS_VEVO));
                                     w_bus_init=11;}
if ((NeedTimer && curmillis - prevNeedTimer>11000) || w_bus_init == 13)  {NeedTimer = 0; 
             if (curmillis - prevNeedTimer>11000) noData = 1; 
             if (needAction == NEED_SMSZAPROS)     SMSzapros();
        else if (needAction == NEED_SERVICEINFO) ServiceINFO();
        else if (needAction == NEED_DTCCLEAR) {startSMS(KTOzapros); SIM800.println (F("DTC not cleared. Heater no answer!")); EndSMS();}
        w_bus_init = 9; noData = 0; needAction = 0; 
        } 
        
 if (needAction==NEED_DTCCLEAR && w_bus_init==10) { sendMessage (HEATER_DTC_ERASE, sizeof(HEATER_DTC_ERASE)); w_bus_init = 20;  }

}


void Reset_gsm (){
  if (millis()-prevReset>(unsigned long)intervalReset*60000UL){
  
  digitalWrite (DTR, LOW); delay (150);
  SIM800.println (F("AT")); 
  timerenabledWaitOK = 1; timerWaitOK = millis();
  gsmOK = false;
  prevReset = millis(); }

 if (timerenabledWaitOK && millis()-timerWaitOK>6000) {
    timerenabledWaitOK = 0;
    if (!gsmOK) {
      SIM800.println (F("AT")); timerenabledWaitOK = 1; timerWaitOK = millis();
      NoAnswersGSM++; if (NoAnswersGSM>4) NoAnswersGSM = 4; 
      
      }
}

  
 if (!gsmOK)  { 
  if (SIM800.available()>0){                                   
    char currSymb = SIM800.read(); 

  

    if ('\r' == currSymb) {                                      
                                  
       if (!currStr.compareTo("OK")) {   gsmOK = true;  timerenabledWaitOK = 0; NoAnswersGSM=0; digitalWrite (DTR, HIGH);}
       currStr = "";                                           
    }
    
    else if ('\n' != currSymb && currSymb!=0x13 && currSymb!=0x11) {currStr += String(currSymb);}}}
    
    
    if (NoAnswersGSM>=4) Reset();
    
    }



 
 void Reset(){
     
      if (!resettimer) {digitalWrite (ResetGSM, RelayON); resettimer = 1; resetTimer = millis();} 
else if (millis()- resetTimer>6000 ) {
resettimer = 0; 
NoAnswersGSM=0; 
ResetNumber++; 
EEPROM.write (ResetNumber_cell, ResetNumber);
digitalWrite (ResetGSM, !RelayON); 
delay (3500); NastroykaGSM ();}
             }




void sendMessage(const byte *command, const size_t size){

 Initreset = 1;  prevInitreset = curmillis;  // включение таймера сброса инита
 
 if (Heater == TTC_E){
  const byte siZe = size+4;
  byte Mes[siZe];
  byte Checksum = 0;
  for(byte i=0; i<siZe; i++) {
    if (i==0) {Mes[i]=size; bitWrite(Mes[i], 7 , 1);}
    if (i==1) Mes[i] = 0x51;
    if (i==2) Mes[i] = 0xF1;    
    if (i==3) {for (byte t=0; t<size; t++ ) {Mes[i]=command[t]; Checksum+=Mes[i] ;K_LINE.write (Mes[i]);  i++;}}
    if (i!=siZe-1) Checksum+=Mes[i];
    else Mes[i] = Checksum;    
    K_LINE.write (Mes[i]); 
      }
  
 }
 else if (Heater == EVO || Heater == VEVO){
  const byte siZe = size+3;
  byte Mes[siZe];
  byte Checksum = 0;
  for(byte i=0; i<siZe; i++) {
    if (i==0) Mes[i] = 0xF4;
    if (i==1) Mes[i]=size+1; 
    if (i==2) {for (byte t=0; t<size; t++ ) {Mes[i]=command[t]; Checksum^=Mes[i] ;K_LINE.write (Mes[i]); i++;}}
    if (i!=siZe-1) Checksum^=Mes[i];
    else Mes[i] = Checksum;    
    K_LINE.write (Mes[i]); 
      }
  
  }
  }

 

dimabos09
Offline
Зарегистрирован: 14.01.2019

Спасибо!

dimabos09
Offline
Зарегистрирован: 14.01.2019

Ещё раз благодарю за Ваш труд!

Pashok3D
Offline
Зарегистрирован: 20.01.2019

в плате тоже  городят изменения ? 

seowayder
Offline
Зарегистрирован: 01.10.2019

Добрый день! Подскажите пожалуйста, с автономкой на БМВ е46 будет работать по к-линии? Что может?

MaksVV
Offline
Зарегистрирован: 06.08.2015

а есть ли жизнь на Марсе? Если вы снимете лог общения диагностики с вашим котлом, то я скажу, будет или нет. 

seowayder
Offline
Зарегистрирован: 01.10.2019

Понял, спасибо. Когда порадуете mqtt версией?)

P.S. Есть кто с Украины готовый продать одну печатку готовую?

Pashok3D
Offline
Зарегистрирован: 20.01.2019

seowayder пишет:

Понял, спасибо. Когда порадуете mqtt версией?)

P.S. Есть кто с Украины готовый продать одну печатку готовую?

 

Я , скоро у китайцев буду заказывать 

MaksVV
Offline
Зарегистрирован: 06.08.2015

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

seowayder
Offline
Зарегистрирован: 01.10.2019

Было бы круто, а то холодно уже))

YuriL
Offline
Зарегистрирован: 21.01.2019

MaksVV пишет:
Постараюсь подправить в ближайшее время плату. Добавив конденсатор и диоды, чтобы развязать питание мк и джсм . После этого можно в заказ

Я тут немного пробовал поменять все местами( развернул модуль, чтобы можно было sim вставить не разбирая корпуса) и под свой корпус, но теперь не уверен в правильности разводки. Может закину свой проект и библиотеки элементов, а вы сможете глянуть на правильность?

MaksVV
Offline
Зарегистрирован: 06.08.2015

не, это самостоятельно. 

vgk_com
Offline
Зарегистрирован: 02.03.2017

Добрый вечер! Наконец-то добрался до сборки платы, скоро зима а я еще не опробовал. Сижу второй вечер, уже мозги кипят, а плата не хочет работать. Не пойму в чем дело. Уже ради пробы просто подключил UNO к сим800 модулю проводами без платы, залил сперва очищающую прошивку потом прошивку v.3.66 и ни как не реагирует на смс запрос номеров ни на добавление номера. Обратных смс нет. Деньги на симке есть. Не чего не трогая перепрошиваю на другой  код проверки сим800, все работает и смс отправляет и принимает. 

При проверки работы к плате кроме питания не чего не подключал. СМС без подключения котла работать ведь должны?

MaksVV
Offline
Зарегистрирован: 06.08.2015

да, прошивка 3.66 это не для вас. надо 3.65

MaksVV пишет:
v3.66 , это 3,65 переделанный под 11 значный номер тел.

MaksVV
Offline
Зарегистрирован: 06.08.2015

плата 8.91. и    Гербер файлы для отправки на изготовление в Китай рекомендую здесь . Развязал питание  сим800 и ардуины через диоды и добавил кондёр по питанию. Теперь на dc-dc нужно будет настроить такое напряжение, чтобы после диода на сим800 было 4В. Думаю это будет около 5В. Проверяйте, лишним не будет. Косяки не исключены. 

vgk_com
Offline
Зарегистрирован: 02.03.2017

Да я обе пробовал и 3.66 возвращал на телефон 12 цифр. В принципе на голой плате СИМ800 должен же отвечать.