Сопряжение базовой станции Misol Arduino с локальной сетью

Основой данной публикации являются два ранее разработанных скетча: Перехват данных от метеостанции Misol Arduino и Передача данных базовой станции Misol Arduino в локальную сеть и Интернет (Народный мониторинг). Требуется объединить эти два скетча в один и обеспечить отправку метеоданных, перехватываемых из пакета метеостанции Misol, в локальную сеть широковещательным пакетом и на сервер народного мониторинга.

Объединенный скетч

/*
  Cкетч:
    перехватывает пакеты данных метеостанции Misol;
    конфигурирует контроллер W5100 Arduino для работы с протоколом UDP и
    передает строку широковещательным пакетом в локальную сеть
    и на сервер Народного мониторинга.
*/

#include <Ethernet.h>
#include <EthernetUdp.h>

// ----- ***** ----- ***** ----- NET DATA ----- ***** ----- ***** -----
// ----- ***** ----- LOCAL DATA ----- ***** -----
byte MyMAC[] = { 0x3A, 0xF1, 0x7F, 0xA4, 0x56, 0x7E };  // MAC для идентификации устройства
// сервером народного мониторинга
IPAddress MyIP ( 192, 168, 0, 199 );
IPAddress MyDNS  ( 192, 168, 0, 1 );
IPAddress MyGateway ( 192, 168, 0, 1 );
IPAddress MySubnet ( 255, 255, 255, 0 );
unsigned int localPort = 9999;            // Порт для приема пакетов UDP
IPAddress NMDNS;
// ----- End LOCAL DATA -----

// ----- ***** ----- Broadcast udp message ----- ***** -----
IPAddress IPBC( 192, 168, 0, 255 );
const unsigned int PORTBC = 8887;         // Порт для отправки пакетов UDP
// ----- End Broadcast -----

// ----- ***** ----- NM ----- ***** -----
byte IPNMDNS[4];    //Для DNS
byte IPNM[] = { 185, 245, 187, 136 };     // IP сервера народного мониторинга.
// Не требуется при включении DNS
int portNM = 8283;
String mac, mac_d;
// ----- End NM -----
// ----- ***** ----- End NET DATA ----- ***** -----

EthernetUDP Udp;            // Определение UDP

#define LUTime 60000;       // Периодичность передачи пакетов локальным пользователям миллисекунды (1 минута)
#define NMTime 300000;      // Периодичность передачи пакетов на народный мониторинг миллисекунд (5 минут)
long TxLUTime, TxNMTime;


// ----- ***** ----- Определения перехвата пакета ----- ***** -----
volatile byte bitmas[528];
volatile byte tetramas[132];
byte rxb;                    // Значение принятого бита
volatile int nbit = 0;
byte nbyte = 0;
byte rxpin = 2;              // Назначен пин 2 ExtInt0
volatile byte rxpinold, rxpinnew;     // Значения входа

volatile unsigned long timpb, timpe, timp, tpause, timpem ;   //Время начала, конца импульса, паузы
volatile byte imprx;

float Temp, TempAv, Hum, AW, GW, RnC;
float TempI[4];
bool TempValid = false;
String RW;
byte DW;
int NDW;
uint16_t Illum;
bool dataHWSRecive = false;
bool dataPreparation = false;

#define CRC3B   40  // Контрольная сумма первых трех байт. Отличается для каждого устройства! Считается по строке приема.
// ----- Конец Определения перехвата пакета -----


// ----- ***** ----- ***** ----- Setup ----- ***** ----- ***** -----
void setup() {

  // ----- ***** ----- W5100 ----- ***** -----
  Ethernet.begin(MyMAC, MyIP);          // Инициализация контроллера W5100 с заданными параметрами
  Serial.begin(115200);                 // Инициализация последовательного порта
  while (!Serial) {                     // Ожидание инициализации последовательного порта
    ;
  }
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {    // Проверка наличия контроллера W5100
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1);                         // Остановка исполнения при отсутствии контроллера W5100
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }
  Udp.begin(localPort);         // Запуск службы UDP
  // ----- End W5100 -----

  attachInterrupt(0, int0rxreceive, CHANGE);    //Подпрограмма обработки принимаемого импульса на 2 DPIN (Interrupt 0)

  Serial.begin(115200);

  //Разметка для экранного вывода данных
  Serial.println("  Sync__  Serial__ Tempera_  Humid  AvWin GstWn UK RC_____ LB DW  CRC__");

}   // ----- End Setup -----


// ----- ***** ----- ***** ----- Loop ----- ***** ----- ***** -----
void loop() {


  //  ----- ***** ----- Перехват пакета ----- ***** -----
  // *** Count Pause ***
  tpause = millis() - timpem;

  if (imprx == 1 && tpause > 200) {

    //****** Вывод пакета данных по тетрадам
    Serial.print(": ");

    //Сброс массива байтов
    for (int i = 0; i < 132; i++) {
      tetramas[i] = 0;
    }

    // *** Преобразование массива бит в массив тетрад
    byte nbyte = 0;
    byte j = 0;
    byte l = 0;
    byte k = 8;
    for (int i = 0; i < nbit; i++ ) {
      tetramas[l] = tetramas[l] + bitmas[i] * k;
      k = k / 2;
      j++;
      if (j == 4) {
        j = 0;
        l++;
        k = 8;
        Serial.print(tetramas[l - 1]);
        Serial.print(", ");
      }
    }
    Serial.println("***** ");
    //***

    //Контрольная сумма первых трех тетрад
    int sum = 0;
    for (byte i = 0; i < 3; i++) {
      sum = sum + tetramas[i];
    }

    //***** Рабочий цикл
    if ( sum == CRC3B) {
      //Преобразование тетрадных значений в float
      //Температура Temp
      int q = 256;
      byte s = 5;
      float Temp = 0;
      for (byte i = 0; i < 3; i++) {
        Temp = Temp + q * tetramas[i + s];
        q = q / 16;
      }
      Temp = (Temp - 400) / 10;
      Serial.print("Temperature = ");
      Serial.print(Temp);
      Serial.println(" *C");

      //Влажность Hum
      q = 16;
      s = 8;
      float Hum = 0;
      for (byte i = 0; i < 2; i++) {
        Hum = Hum + q * tetramas[i + s];
        q = q / 16;
      }
      Serial.print("Humidity    = ");
      Serial.print(Hum);
      Serial.println(" %");

      //Средняя скорость ветра AW
      q = 16;
      s = 10;
      float AW = 0;
      for (byte i = 0; i < 2; i++) {
        AW = AW + q * tetramas[i + s];
        q = q / 16;
      }
      AW = AW * 0.34;
      Serial.print("AW          = ");
      Serial.print(AW);
      Serial.println(" mps");

      //Скорость ветра в порыве GW
      q = 16;
      s = 12;
      float GW = 0;
      for (byte i = 0; i < 2; i++) {
        GW = GW + q * tetramas[i + s];
        q = q / 16;
      }
      GW = GW * 0.34;
      Serial.print("GW          = ");
      Serial.print(GW);
      Serial.println(" mps");

      // Счетчик осадков Rn
      q = 256;
      s = 15;
      float RnC = 0;
      for (byte i = 0; i < 3; i++) {
        RnC = RnC + q * tetramas[i + s];
        q = q / 16;
      }
      RnC = RnC * 0.3;
      Serial.print("Rain        = ");
      Serial.print(RnC);
      Serial.println(" mm");

      // Направление ветра
      byte DW = tetramas[19];
      Serial.print("DW          = ");
      Serial.print(DW);
      Serial.println("  N");

      switch (DW) {
        case 0: RW = "N";         break;
        case 1: RW = "NNE";       break;
        case 2: RW = "NE";        break;
        case 3: RW = "ENE";       break;
        case 4: RW = "E";         break;
        case 5: RW = "ESE";       break;
        case 6: RW = "SE";        break;
        case 7: RW = "SSE";       break;
        case 8: RW = "S";         break;
        case 9: RW = "SSW";       break;
        case 10: RW = "SW";       break;
        case 11: RW = "WSW";      break;
        case 12: RW = "WSW";      break;
        case 13: RW = "W";        break;
        case 14: RW = "NW";       break;
        case 15: RW = "NNW";      break;
        default: RW = "ND";
      }
      Serial.print("RW = ");
      Serial.println(RW);

      NDW = DW * 22.5; //Преобразование к градусам

    } //*** Окончание рабочего цикла

    //Подготовка нового цикла приема пакета данных
    nbit = 0;
    imprx = 0;
  } // ----- Конец Перехват пакета -----


  //  ----- ***** ----- Отправка пакета локальным пользователям ----- ***** -----
  if (TxLUTime < millis()) {    // Передача пакета локальным пользователям

    //  ----- ***** ----- Формирование строки локальным пользователям ----- ***** -----
    String strlip;
    strlip = String(Temp) + '#' + String(Hum) + '#' +                         //Метео параметры
             String(AW) + '#' + String(GW) + '#' + String(DW) + '#' +       //Ветер
             String(RnC);                                                    //Осадки

    Serial.print("StrLip=: ");
    Serial.print(strlip);
    //  ----- Конец Формирование строки локальным пользователям -----

    //  ----- ***** ----- Преобразование строки в массив символов ----- ***** -----
    uint16_t lenBClip = strlip.length();
    Serial.print("\tLen LIP=: ");
    Serial.println(lenBClip);
    char ttsBClip[lenBClip + 1];
    strcpy(ttsBClip, strlip.c_str());
    // ----- Конец Преобразование строки в массив символов -----

    //  ----- ***** ----- Отправка пакета (массива символов) ----- ***** -----
    Udp.beginPacket(IPBC, PORTBC);
    Udp.write(ttsBClip);
    Udp.endPacket();
    // ----- Конец Отправка пакета (массива символов) локальным пользователям -----

    //  ----- ***** ----- Задание времени отправки очередного пакета ----- ***** -----
    TxLUTime += LUTime;
    // ----- Конец Задание времени отправки очередного пакета -----

  }  // ---- Конец Передача пакета локальным пользователям ---- -
  //  ----- Конец Отправка пакета локальным пользователям -----


  //  ----- ***** ----- Отправка пакета серверу народного мониторинга ----- ***** -----
  if (TxNMTime < millis()) {

    Serial.println("\nString to NM: ");
    String strNM;
    strNM = "#" + mac_d +  "\n" +
            "#MIS_T#" + String(Temp)  + "\n"
            "#MIS_H#" + String(Hum)   + "\n"
            "#MIS_AW#" + String(AW)   + "\n"
            "#MIS_GW#" + String(GW)   + "\n"
            "#MIS_DW#" + String(NDW)  + "\n"
            "#MIS_RNC#" + String(RnC) + "\n"
            + "##";
    Serial.println(strNM);

    uint16_t lenNM = strNM.length();
    Serial.print("Len strNM=: ");
    Serial.println(lenNM);
    char ttsNM[lenNM + 1];
    strcpy(ttsNM, strNM.c_str());

    Udp.beginPacket(IPNM, portNM);
    Udp.write(ttsNM);
    Udp.endPacket();

    TxNMTime += NMTime;
  }
  // ----- Конец Отправка пакета серверу народного мониторинга -----

}   // ----- Конец Loop -----


// ----- ***** ----- ***** ----- Подпрограммы ----- ***** ----- ***** -----

// ----- ***** ----- Прием импульса ----- ***** -----
void int0rxreceive() {
  rxpinold = rxpinnew;      //Сохранение предшествующего состояния
  rxpinnew = digitalRead(rxpin);  //Получение нового значения

  //Анализ состояний
  if (rxpinold == LOW && rxpinnew == HIGH) { // *** Фронт импульса
    //Старт приема импульса
    timpb = micros();
  }

  else if (rxpinold == HIGH && rxpinnew == LOW) // *** Спад импульса
  { //Окончание приема импульса
    timpe = micros();
    timpem = millis();
    timp = timpe - timpb;


    if (timp > 450 && timp < 550) {
      rxb = 1;
    }
    else if ( timp > 1250 && timp < 1550) {
      rxb = 0;
    } //Окончание принятия решения

    else {
      Serial.print("/ \n");
      goto noimp;
    }
    bitmas[nbit] = rxb; //Присвоение значения бита элементу массива
    nbit++;             //Определение позиции следующего бита
    imprx = 1;          // Флаг вывода данных

noimp: {
    }
  }
} // ------ Конец Прием импульса -----

// ---- ***** ---- Окончание подпрограмм ---- ***** ----

Дальнейшим направлением развития проекта является расширение функциональных возможностей метеостанции MiSol Arduino за счет измерения значений дополнительных параметров: освещенности, индекса ультрафиолетового измерения, плотности пыли и т.д., а также, сопряжение с приемником GPS с целью получения координат и точного времени.