Автономная полевая метеостанция.

Iguana
Offline
Зарегистрирован: 22.02.2016
Пока это не совсем уж метеостанция ибо измеряет только температуру. Но в данный момент больше и не требуется. Ибо недалеко от места, где она установлена, есть станция на esp8266, которая передает еще и давление и влажность. Поскольку на даче нет вайфая и нет целесообразности его там получать (т.е. тратить деньги на мобильный роутер и отдельный тариф для него) было решено задействовать gsm. И сделать станцию независимой по электропитанию. Небольшой опыт работы с солнечными панелями и акб 18650 уже на той же даче имеется (радиолюбительский qrpp маячек работает скоро уже как год), а вот опыта работы с gsm модулями не было. Поэтому первый выбор был крайне неудачный - А6. Но он мне понравился на али, тем более где то как то в инете прочитал, что команды в нем совместимые с sim800 и выписал из Китая. По приходу оказалось все значительно хуже. АТ-комманды там другие и вообще с модулем какие-то проблемы. Перегрузить с пина ардуины не получалось, только физическим контактом с землей. На вопрос тутова кто как перегружает не ответил никто, видно шибко сложный вопрос был))). И возникла вторая проблема - код. По началу была надежда на интернет в котором как и в Греции все есть, но увы... А ознакомившись с различными проектами с модулями понял, что самостоятельно я код не напишу, а если и упрусь, то только лет за несколько.... 
А весна уже подпирала и кулубника(с) требовала данных))). На форуме был брошен клич и из всего богатства выбора откликлнулся лишь один человек - phoenixoid. Техзадание было простое. Каждые 10 минут станция должна была скидывать на сайт thingspeak.com два показания температуры: приземного воздуха и почвы на глубине 5 см и показание напряжения на акб. Почему именно на этот сайт? Да фиг его знает, нравится он мне своей простотой и тем, что есть хорошее приложение по нему для адндроида. Код был написан, но запустить на А6 так и не получилось. Тогда phoenixoid переписал код под sim800l и прислал мне его по почте, ибо с али было ждать долго по весне. А я ему для опытов отправил А6. В результате вся конструкция прошла испытания на столе дома, а потом перенесена на дачу. Вот и вся предыстория, теперь детали.
Общий вид конструкции. Видно отдельно плату питания на которой установлены зарядник 1а для одного 18650, преобразоваль dc-dc step up, который выдает 4,1 вольта на выходе и три параллельных акб. Сначала был один, его не хватало. В проекте маячка его хватат для питания конструкции, но она ночью не работает. А здесь передача данных  идет круглосуточно. Потом добавился один и в процессе эксплуатации по нышешним грустнопогоднодождливым дням был добавлен третий)). Конечно это плохо, ибо заряжаются они наверняка не ровно, но работают, а это главное)). На второй плате ардуино промини и сам модуль sim800l. Кнопка красная это ресет. Внизу выключатель отключает питание от схемы, но не от акб. И две колодки: солнечные панели и два градусника ds18b20.
Все это было засунуто в электрораспаячную коробку и закреплено в быстросколоченный ящик из osb. Есть мысль офороми все покрасивше в металле и пр., но пока все как есть так и работает)).
Теперь про опсоса. Дача у меня находится в интересном месте с точки зрения сотовых сетей. На границе с Татарией. Т.е. иногда бывает, что пройдя сто метров в какую нибудь сторону, получаешь смс с сообщением с выходом из домашней сети и приятной поездки по стране и соответственно вернувшись сто метров назад, получаешь еще одно сообщение с поздравлениями о приятном возвращении домой)).  Вначале стояла билайновская симка. Были проблемы с пропусками передачи данных от нескольких минут до нескольких часов. Поставил мегафон. Вроде меньше пропусков стало, но все равно оставались промежутки. Мтсовская симка сразу заявила, что находится в чужом регионе и тариф будет соответсвтующий. Пришлось остановиться на мегафоне и сделать выносную антенну.
Стоит все это и работает с 6го мая 2017 года. Планирую оставить и на зиму для спытаний на прочность всего конструктива, но придется поднимать выше, ибо заносит там снегом выше пояса)). Смотреть за показаниями можно тут https://thingspeak.com/channels/249765
Сейчас солнечных панелей добавлено еще три ряда. За три пасмурных дня вольтаж не опускался ниже 4,1 вольта. Причем надо отнимать еще 0,1 - 0,2 вольта. Надо бы дельту забить в скетч, но все руки не доходят.
Теперь сам код.
#include <SoftwareSerial.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#define modemReset 10 //Пин для перезагрузки модема
#define ONE_WIRE_BUS 4 //Пин для датчиков
#define battery A0 //Пин для напряжения батареи
#define TEMPERATURE_PRECISION 11
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress firstThermometer = { 0x28, 0xFF, 0x1F, 0x73, 0x61, 0x16, 0x04, 0x52 };
DeviceAddress secondThermometer = {  0x28, 0xFF, 0x04, 0x87, 0x61, 0x16, 0x04, 0x21 };

byte opsos = 0; // 0 Билайн, 1 Мегафон, 2 МТС
int sleepSeconds = 600; //Пауза между отправками в секундах
String defaultRequest = "AT+HTTPPARA=\"URL\",\"http://api.thingspeak.com/update?api_key=W6MQMHLIT0H0OB3B&field1=";
String actionRequest = "";
char modemAnswer[65];

float temp1 = 0;
float temp2 = 0;
float batteryVoltage = 0;
int httpSt = 0;
byte sendTries = 0;
SoftwareSerial sim800SS(2, 3); // RX, TX

void readModemAnsw() {
  for (byte i = 0; i <= 63; i++) {
    modemAnswer[i] = 0x00;
  }
  byte i = 0;
  byte inByte = 0;
  while (sim800SS.available() != 0) {
    inByte = sim800SS.read();
    if ( inByte != 10 && inByte != 13) {
      modemAnswer[i] = inByte;
      i++;
    }
    delay(10);
  }
Serial.print("Modem Answer: ");
  Serial.println(modemAnswer);
}

int csq () {
  char char_csq[3];
  sim800SS.println(F("AT+CSQ"));
  delay(500);
  readModemAnsw();
  char_csq[0] = modemAnswer[6];
  char_csq[1] = modemAnswer[7];
  return atoi(char_csq);
}

bool gprsInit() {
  sim800SS.println(F("AT+SAPBR=0,1"));
  delay(500);
  readModemAnsw();
  sim800SS.println(F("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\""));
  delay(500);
  readModemAnsw();
  switch (opsos) {
    case 0: //Билайн
      sim800SS.println(F("AT+SAPBR=3,1,\"APN\",\"internet.beeline.ru\""));
      delay(500);
      sim800SS.println(F("AT+SAPBR=3,1,\"USER\",\"beeline\""));
      delay(500);
      sim800SS.println(F("AT+SAPBR=3,1,\"PWD\",\"beeline\""));
      delay(500);
      readModemAnsw();
      break;
    case 1: //Мегафон
      sim800SS.println(F("AT+SAPBR=3,1,\"APN\",\"internet.megafon.ru\""));
      delay(500);
      sim800SS.println(F("AT+SAPBR=3,1,\"USER\",\"gdata\""));
      delay(500);
      sim800SS.println(F("AT+SAPBR=3,1,\"PWD\",\"gdata\""));
      delay(500);
      readModemAnsw();
      break;
    case 2: //МТС
      sim800SS.println(F("AT+SAPBR=3,1,\"APN\",\"internet.mts.ru\""));
      delay(500);
      sim800SS.println(F("AT+SAPBR=3,1,\"USER\",\"mts\""));
      delay(500);
      sim800SS.println(F("AT+SAPBR=3,1,\"PWD\",\"mts\""));
      delay(500);
      readModemAnsw();
      break;
  }

  sim800SS.println(F("AT+SAPBR=1,1"));
  delay(1000);
  readModemAnsw();
  byte i = 0;
  do {
    sim800SS.println(F("AT+SAPBR=2,1"));
    delay(1000);
    readModemAnsw();
    i++;
  } while (modemAnswer[10] != '1' && i < 15);
  if (i < 15) {
    return true;
  } else {
    return false;
  }
}

void restartModem() {
  Serial.println(F("Restart modem"));
  byte errCount = 0;
  digitalWrite(modemReset, LOW);
  delay(1000);
  digitalWrite(modemReset, HIGH);
  delay(20000);
  readModemAnsw();

  //Проверяем связь с модемом
  sim800SS.println(F("ATE0"));
  delay(500);
  readModemAnsw();
  if (modemAnswer[0] == 'A' && modemAnswer[1] == 'T' && modemAnswer[2] == 'E' && modemAnswer[3] == '0' && modemAnswer[4] == 'O' && modemAnswer[5] == 'K') {
    //Проверяем установлена ли СИМ карта

    sim800SS.println(F("AT+CSMINS?"));
    delay(500);
    readModemAnsw();
    if (modemAnswer[11] == '1') {
      //Проверяем уровень GSM сигнала
      if (csq() < 2) {
        Serial.println(F("Low signal!"));
      }

      //Поднимаем GPRS
      if (gprsInit() == false)  {
        Serial.println(F("GPRS init Error!"));
        restartModem();
      } else {
        Serial.println(F("GPRS init OK"));
      }

    } else {
      Serial.println("No Sim Card");
    }
  } else {
    Serial.println("Modem Error");
  }
}

void httpTerm() {
  sim800SS.println(F("AT+HTTPTERM"));
  delay(500);
  readModemAnsw();
}

void httpRequest(String Request) {
  int i = 0;
  Serial.println("HTTP INIT");
  sim800SS.println(F("AT+HTTPINIT"));
  delay(500);
  readModemAnsw();

  Serial.println(Request);
  sim800SS.println(Request);
  delay(500);
  readModemAnsw();

  Serial.println("HTTP ACTION");
  // Выполняем HTTP запрос и записываем ответ в строку
  sim800SS.println(F("AT+HTTPACTION=0"));
  for (int i = 0; i < 30; i++) {
    readModemAnsw();
     if ((modemAnswer[0] == '+' && modemAnswer[1] == 'H') || (modemAnswer[0] == 'E' && modemAnswer[1] == 'R')){
      break;
     }
    delay(1000);
  }
  
  // Если модем ответил "ОК"
  if (modemAnswer[0] == '+' && modemAnswer[1] == 'H' && modemAnswer[2] == 'T') {
    char httpStatus[4];
    httpStatus[0] = modemAnswer[15];
    httpStatus[1] = modemAnswer[16];
    httpStatus[2] = modemAnswer[17];
    httpSt = atoi(httpStatus);
    Serial.print("HTTP status: ");
    Serial.println(httpSt);
    // Если HTTP статус 200 (ОК)
    if (httpSt == 200 || httpSt == 302) {
      httpTerm();
    } else {
      char g[2];
      g[0] = httpStatus[0];
      int j = atoi(g);
      if (j = 6) {
        restartModem();
      }
    }
  } else {
    Serial.println("HTTP send error!");
    restartModem();
  }
}

void setup() {
  // Инициалируем UART
  Serial.begin(9600);
  sim800SS.begin(9600);
  sim800SS.listen();
  //Инициализируем входы и выходы

  pinMode(modemReset, OUTPUT);
  pinMode(battery, INPUT);
  sensors.begin();
  sensors.setResolution(firstThermometer, TEMPERATURE_PRECISION);
  sensors.setResolution(secondThermometer, TEMPERATURE_PRECISION);

}

void loop() {
  digitalWrite(13, LOW);
  restartModem();
  sensors.requestTemperatures();
  temp1 = sensors.getTempC(firstThermometer);
  temp2 = sensors.getTempC(secondThermometer);
  int value = analogRead(battery);
  batteryVoltage = (value / 1023.0) * 5;
  actionRequest = (defaultRequest + (temp1) + "&field2=" + (temp2) + "&field3=" + (batteryVoltage) +  "\"");
  sendTries = 0;
  httpSt = 0;
  do {
    httpRequest(actionRequest);
    sendTries++;
    if (httpSt == 200 || httpSt == 302) {
      break;
    }
  } while (sendTries < 10);
  sim800SS.println(F("AT+CPOWD=1"));
  for (int i = 0; i < sleepSeconds; i++) {
    Serial.print("Sleep ");
    Serial.print((sleepSeconds - i));
    Serial.println(" second");
    delay(1000);
  }
}

 

Ко мне по поводу кода не обращаться, ибо я его разобрал для себя по полочкам, что-то понял, что-то нет. Автору кода я ссылку на тему скину, так что все вопросы по коду к нему. По технической части советы принимаются)).
ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

Мне вот интересно, как себя будут вести ваши 18650 аккумуляторы при минус 10, минус 20, минус 30 и даже минус 40?

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

ulis пишет:

Мне вот интересно, как себя будут вести ваши 18650 аккумуляторы при минус 10, минус 20, минус 30 и даже минус 40?

Тоже интересно. Для себя пока так и не уяснил. В основном пишут, что просто не заряжаются, или ждать еще какой бяки? (Хочу радиозвонок на них переделать. Передающую часть, приемная от липошки год нормально работает).

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

bwn пишет:

Тоже интересно. Для себя пока так и не уяснил. В основном пишут, что просто не заряжаются, или ждать еще какой бяки? (Хочу радиозвонок на них переделать. Передающую часть, приемная от липошки год нормально работает).

Это я к тому, что у себя я поставил кислотный аккумулятор, от ИБП на 12 вольт

Iguana
Offline
Зарегистрирован: 22.02.2016

Вот вместе и посмотрим, как они себя поведут! Ссылка на данные есть, до глубокого снега я менять ничего не буду, потом перенесу выше. Хотя зимой она мне на даче и не нужна. Как я писал выше, есть еще один проект на 18650 работающий уже год. -40 к счастью еще не было, но -32 было - работает. Правда там ток порядка 150 ма 30 сек через каждые 5 минут в течении дня, ночью перерыв.

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

Iguana пишет:

Вот вместе и посмотрим, как они себя поведут! Ссылка на данные есть, до глубокого снега я менять ничего не буду, потом перенесу выше. Хотя зимой она мне на даче и не нужна. Как я писал выше, есть еще один проект на 18650 работающий уже год. -40 к счастью еще не было, но -32 было - работает. Правда там ток порядка 150 ма 30 сек через каждые 5 минут в течении дня, ночью перерыв.

По спецификации вроде как должны работать до минус 20, но по опыту (в машине лежит шуруповерт с батареей их трех 18650), уже при минусовой темпереатуре еле крутит.

yucan
Offline
Зарегистрирован: 20.04.2015

Всё таки удалось на А6 запустить?

Что то код не компилируется...

sketch_jul18a:16: error: expected ',' or ';' before 'http'
sketch_jul18a.ino: In function 'void loop()':
sketch_jul18a:228: error: 'actionRequest' was not declared in this scope

Iguana
Offline
Зарегистрирован: 22.02.2016

yucan пишет:

Всё таки удалось на А6 запустить?

Что то код не компилируется...

Нет, А6 лежит в коробке, ждет когда кто-нибудь рабочее для него сделает))

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

#include <SoftwareSerial.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#define modemReset 10 //Пин для перезагрузки модема
#define ONE_WIRE_BUS 4 //Пин для датчиков
#define battery A0 //Пин для напряжения батареи
#define TEMPERATURE_PRECISION 11
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress firstThermometer = { 0x28, 0xFF, 0x1F, 0x73, 0x61, 0x16, 0x04, 0x52 };
DeviceAddress secondThermometer = {  0x28, 0xFF, 0x04, 0x87, 0x61, 0x16, 0x04, 0x21 };

byte opsos = 0; // 0 Билайн, 1 Мегафон, 2 МТС
int sleepSeconds = 600; //Пауза между отправками в секундах
String defaultRequest = "AT+HTTPPARA=\"URL\",\"http://api.thingspeak.com/update?api_key=W6MQMHLIT0H0OB3B&field1=";
String actionRequest = "";
char modemAnswer[65];

float temp1 = 0;
float temp2 = 0;
float batteryVoltage = 0;
int httpSt = 0;
byte sendTries = 0;
SoftwareSerial sim800SS(2, 3); // RX, TX

void readModemAnsw() {
  for (byte i = 0; i <= 63; i++) {
    modemAnswer[i] = 0x00;
  }
  byte i = 0;
  byte inByte = 0;
  while (sim800SS.available() != 0) {
    inByte = sim800SS.read();
    if ( inByte != 10 && inByte != 13) {
      modemAnswer[i] = inByte;
      i++;
    }
    delay(10);
  }
Serial.print("Modem Answer: ");
  Serial.println(modemAnswer);
}

int csq () {
  char char_csq[3];
  sim800SS.println(F("AT+CSQ"));
  delay(500);
  readModemAnsw();
  char_csq[0] = modemAnswer[6];
  char_csq[1] = modemAnswer[7];
  return atoi(char_csq);
}

bool gprsInit() {
  sim800SS.println(F("AT+SAPBR=0,1"));
  delay(500);
  readModemAnsw();
  sim800SS.println(F("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\""));
  delay(500);
  readModemAnsw();
  switch (opsos) {
    case 0: //Билайн
      sim800SS.println(F("AT+SAPBR=3,1,\"APN\",\"internet.beeline.ru\""));
      delay(500);
      sim800SS.println(F("AT+SAPBR=3,1,\"USER\",\"beeline\""));
      delay(500);
      sim800SS.println(F("AT+SAPBR=3,1,\"PWD\",\"beeline\""));
      delay(500);
      readModemAnsw();
      break;
    case 1: //Мегафон
      sim800SS.println(F("AT+SAPBR=3,1,\"APN\",\"internet.megafon.ru\""));
      delay(500);
      sim800SS.println(F("AT+SAPBR=3,1,\"USER\",\"gdata\""));
      delay(500);
      sim800SS.println(F("AT+SAPBR=3,1,\"PWD\",\"gdata\""));
      delay(500);
      readModemAnsw();
      break;
    case 2: //МТС
      sim800SS.println(F("AT+SAPBR=3,1,\"APN\",\"internet.mts.ru\""));
      delay(500);
      sim800SS.println(F("AT+SAPBR=3,1,\"USER\",\"mts\""));
      delay(500);
      sim800SS.println(F("AT+SAPBR=3,1,\"PWD\",\"mts\""));
      delay(500);
      readModemAnsw();
      break;
  }

  sim800SS.println(F("AT+SAPBR=1,1"));
  delay(1000);
  readModemAnsw();
  byte i = 0;
  do {
    sim800SS.println(F("AT+SAPBR=2,1"));
    delay(1000);
    readModemAnsw();
    i++;
  } while (modemAnswer[10] != '1' && i < 15);
  if (i < 15) {
    return true;
  } else {
    return false;
  }
}

void restartModem() {
  Serial.println(F("Restart modem"));
  byte errCount = 0;
  digitalWrite(modemReset, LOW);
  delay(1000);
  digitalWrite(modemReset, HIGH);
  delay(20000);
  readModemAnsw();

  //Проверяем связь с модемом
  sim800SS.println(F("ATE0"));
  delay(500);
  readModemAnsw();
  if (modemAnswer[0] == 'A' && modemAnswer[1] == 'T' && modemAnswer[2] == 'E' && modemAnswer[3] == '0' && modemAnswer[4] == 'O' && modemAnswer[5] == 'K') {
    //Проверяем установлена ли СИМ карта

    sim800SS.println(F("AT+CSMINS?"));
    delay(500);
    readModemAnsw();
    if (modemAnswer[11] == '1') {
      //Проверяем уровень GSM сигнала
      if (csq() < 2) {
        Serial.println(F("Low signal!"));
      }

      //Поднимаем GPRS
      if (gprsInit() == false)  {
        Serial.println(F("GPRS init Error!"));
        restartModem();
      } else {
        Serial.println(F("GPRS init OK"));
      }

    } else {
      Serial.println("No Sim Card");
    }
  } else {
    Serial.println("Modem Error");
  }
}

void httpTerm() {
  sim800SS.println(F("AT+HTTPTERM"));
  delay(500);
  readModemAnsw();
}

void httpRequest(String Request) {
  int i = 0;
  Serial.println("HTTP INIT");
  sim800SS.println(F("AT+HTTPINIT"));
  delay(500);
  readModemAnsw();

  Serial.println(Request);
  sim800SS.println(Request);
  delay(500);
  readModemAnsw();

  Serial.println("HTTP ACTION");
  // Выполняем HTTP запрос и записываем ответ в строку
  sim800SS.println(F("AT+HTTPACTION=0"));
  for (int i = 0; i < 30; i++) {
    readModemAnsw();
     if ((modemAnswer[0] == '+' && modemAnswer[1] == 'H') || (modemAnswer[0] == 'E' && modemAnswer[1] == 'R')){
      break;
     }
    delay(1000);
  }
  
  // Если модем ответил "ОК"
  if (modemAnswer[0] == '+' && modemAnswer[1] == 'H' && modemAnswer[2] == 'T') {
    char httpStatus[4];
    httpStatus[0] = modemAnswer[15];
    httpStatus[1] = modemAnswer[16];
    httpStatus[2] = modemAnswer[17];
    httpSt = atoi(httpStatus);
    Serial.print("HTTP status: ");
    Serial.println(httpSt);
    // Если HTTP статус 200 (ОК)
    if (httpSt == 200 || httpSt == 302) {
      httpTerm();
    } else {
      char g[2];
      g[0] = httpStatus[0];
      int j = atoi(g);
      if (j = 6) {
        restartModem();
      }
    }
  } else {
    Serial.println("HTTP send error!");
    restartModem();
  }
}

void setup() {
  // Инициалируем UART
  Serial.begin(9600);
  sim800SS.begin(9600);
  sim800SS.listen();
  //Инициализируем входы и выходы

  pinMode(modemReset, OUTPUT);
  pinMode(battery, INPUT);
  sensors.begin();
  sensors.setResolution(firstThermometer, TEMPERATURE_PRECISION);
  sensors.setResolution(secondThermometer, TEMPERATURE_PRECISION);

}

void loop() {
  digitalWrite(13, LOW);
  restartModem();
  sensors.requestTemperatures();
  temp1 = sensors.getTempC(firstThermometer);
  temp2 = sensors.getTempC(secondThermometer);
  int value = analogRead(battery);
  batteryVoltage = (value / 1023.0) * 5;
  actionRequest = (defaultRequest + (temp1) + "&field2=" + (temp2) + "&field3=" + (batteryVoltage) +  "\"");
  sendTries = 0;
  httpSt = 0;
  do {
    httpRequest(actionRequest);
    sendTries++;
    if (httpSt == 200 || httpSt == 302) {
      break;
    }
  } while (sendTries < 10);
  sim800SS.println(F("AT+CPOWD=1"));
  for (int i = 0; i < sleepSeconds; i++) {
    Serial.print("Sleep ");
    Serial.print((sleepSeconds - i));
    Serial.println(" second");
    delay(1000);
  }
}

 

yucan
Offline
Зарегистрирован: 20.04.2015

 А6 у меня тоже в коробке валяется без дела.

Попробовал откомпилировать - те же самые ошибки. Сравнил скетчи - один в один.

Вы какую верчию IDE используете? Я пробовал на 1.06 и на 1.6

phoenixoid
Offline
Зарегистрирован: 14.07.2015

С A6 работать не будет. Он AT+HTTPPARA не понимает.

Iguana
Offline
Зарегистрирован: 22.02.2016

yucan пишет:

 А6 у меня тоже в коробке валяется без дела.

Попробовал откомпилировать - те же самые ошибки. Сравнил скетчи - один в один.

Вы какую верчию IDE используете? Я пробовал на 1.06 и на 1.6

Тут какая то проблема со вставкой кода, появляется такая строка

 "<a href="http://api.thingspeak.com/update? 

Ахрефа никакого быть не должно. Не пойму, тут личных сообщений нету что ли? Напишите мне s.zhushev собака гмайл.ком, я по почте скетч пришлю.

bourdoul
Offline
Зарегистрирован: 08.03.2019

Доброго дня!

А реально этот проект перенести на другой сесвис narodmon.ru? Если это возможно, то как это сделать?