SMS информирование отключения внешнего питания на модеме IOT-GA6

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

- отправка SMS через две минуты (изменяется в скетче) после отключения/включения внешнего питания AC220 V.

- отправка SMS при сработке концевика (пин на землю замкнуть) на секунду (изменяется в скетче). Следующее сообщение отправиться не ранее чем через 10 минут (меняется в скетче).

- административный телефон можно поменять позвонив на железку в первые 30 секунд после окончания инициализации модема.

- используется два светодиода: первый - короткие вспышки раз в 3 секунды - нормальный рабочий режим, вспышка раз в секунду - инициализация модема, частое мецание - ошибка ответа от модема - перезагрузка; второй светодиод - несколько вспышек за 3 секунды = номеру выполняемой команды/шага в данный момент - можно диагностировать на какой команде модем капризничает.

- в каждой отправляемой SMS прописывается uptime железки и температура внешнего датчика DS18B20.

#include <avr/wdt.h>
#include <avr\pgmspace.h>
#include <EEPROM.h>

char phoneMain[] = "7920*******"; // admin phone
const char at21cmd[] PROGMEM = "AT+CUSD=1,*100#,15\r\n"; // USSD string get balance

#define DOOR_CONTROL
#define EXT_POW_CONTROL
#define USE_DS18B20

#ifdef EXT_POW_CONTROL
#define ext_pow_pin (byte)5 // 2 <--> 5 test
#define READEXTPOW digitalRead(ext_pow_pin)
#define delaySMSpowerOFF 120000UL // задержка 2 минут отправки СМС при отключении питания
#define delaySMSpowerON 120000UL // задержка 2 минут отправки СМС при включении питания
unsigned long timer_power_on_off;
byte startPowerTimer;
byte lastPower220;
#endif

#ifdef DOOR_CONTROL
byte deviceMode = 1; // 1 = сигнализация включена  - контроль сработки датчика
#define key_pin (byte)2 // 5 <--> 2 test
#define READKEY !digitalRead(key_pin)
#define delay_alarm_door 600000UL
unsigned long timer_alarm_door = 0;
byte flsend_alarm_door;
#define period_deb_key 1000UL
unsigned long timer_deb_key = 0;
#endif

#ifdef USE_DS18B20
#include <OneWire.h>
#include <DallasTemperature.h>
#define TEMPERATURE_PRECISION 9 // точность получения значения темературы
#define ds18_pin A0 // pin DS18B20
OneWire oneWire(ds18_pin); // объект 1Ware
DallasTemperature sensors(&oneWire); // объект  датчика температуты
byte dsCount; // количество датчиков температуры
#define max_ds_count 5 // максимальное количество датчиков
DeviceAddress massTherm[max_ds_count]; // массив адресов датчиков ds18b20
#define period_get_temp 780137UL // получение температуры каждые 13 min
unsigned long timer_get_temp; // таймер получения температуры
word massTemper[max_ds_count]; //массив температур
byte requestTemp = 1; // запрос температуры
#endif

#define bLedOn LOW
#define led1_pin (byte)9 // status led
#define LED1ON digitalWrite(led1_pin,bLedOn)
#define LED1OFF digitalWrite(led1_pin,!bLedOn)
#define led2_pin  (byte)4 // error led
#define LED2ON digitalWrite(led2_pin,bLedOn)
#define LED2OFF digitalWrite(led2_pin,!bLedOn)
#define reset_A6_pin (byte)7
#define power_A6_pin (byte)8

#define count_ext_commands 4 // count external commands from incoming sms

byte flGetBalance;

byte FirstStart;

#define period_wait_phone 30000UL // ждем 30 секунд после инициализации модема звонка чтоб записать админский номер
unsigned long timer_wait_phone;
byte flag_wait_phone;
#define pos_eeprom_flag_saved_admin_phone 48 // value 139 - exist phone
#define pos_eeprom_admin_phone 76

unsigned long timer_reg_modem; // timer registration modem in net
#define max_size_pgm_buf 128
char pgm_buf[max_size_pgm_buf];
#define period_read_sms 29971UL // read sms every ~30 sec
unsigned long timer_read_sms = 0; // timer read sms
#define period_send_sms 8937UL // send sms every ~9 sec
unsigned long timer_send_sms = 0; // timer read sms

#define max_size_fixed_resp 16 // in work save 3 response from buf commands
char resp1[max_size_fixed_resp]; char resp2[max_size_fixed_resp]; char resp3[max_size_fixed_resp]; // 3 parts response
byte flresp1, flresp2, flresp3; // found parts of response
#define max_size_sms_buf 110 // max size sms with stop byte and text uptime
char sms_buf[max_size_sms_buf]; // sms buf
char sender[13]; // phone number for send sms. +7 and 10 digits + stop byte = always 13 digits!!!
#define max_size_resp_buf 254 // max size response buf from modem, then more than goodest
char resp_buf[max_size_resp_buf]; // response buf from modem
byte pos_buf; // current pos response buf

byte ledStatus, ledError, flLedSt, flLedEr;
// ledError
// 0 - normal work, modem status 101, 1 flash per 3 sec
// 1 - init modem status 100, 1 flash per 1 sec
// 2 - problem modem, no response, flash everu 20 milli sec,reset modem and new start
// ledStatus
// number flash per 3 sec = number modem step < 100
unsigned long timer_led_status, timer_led_error;


byte modem_step; // current work mode mode in table of command
// static steps:
// 100 - delay for registration modem in net
// 101 - not wait response, wait incomming call or other commands

byte wait_response; // 0-no wait response, wait ring or other command
// 1-wait fixed response, if time more - reset modem
#define period_fixed_wait 15000UL // max time for type 1 wait response
// 2-wait response data or wait action user, if time more - clear command
#define period_data_wait 15000UL // max time for type 2 wait response

unsigned long current_millis;

uint8_t mcusr_mirror __attribute__ ((section (".noinit")));
void get_mcusr(void) \
__attribute__((naked)) \
__attribute__((used)) \
__attribute__((section(".init3")));
void get_mcusr(void)
{
  mcusr_mirror = MCUSR;
  MCUSR = 0;
  wdt_disable();
}

void setup() {
  MCUSR = 0; wdt_disable();
  Serial.begin(9600); // modem speed
  // read mainPhone from EEPROM
  if ((EEPROM.read(pos_eeprom_flag_saved_admin_phone) == 139)) {
    for (byte i = 0; i < 11; ++i) phoneMain[i] = EEPROM.read(pos_eeprom_admin_phone + i);
    phoneMain[11] = 0;
  }
#ifdef USE_DS18B20
  sensors.begin(); // инициировать датчики температуры
  dsCount = sensors.getDeviceCount(); // получить количество датчиков
  if (dsCount > max_ds_count) dsCount = max_ds_count; // если датчиков больше чем максимальное - уменьшаем
  oneWire.reset_search(); // сброс шины поиска датчиков
  byte i = 0; while (i < dsCount) { // цикл по всем датчикам
    if (sensors.getAddress(massTherm[i], i)) sensors.setResolution(massTherm[i], TEMPERATURE_PRECISION); ++i;
  }
#endif
  // put your setup code here, to run once:
  initAll();
  wdt_enable(WDTO_8S);
}

void loop() {
  wdt_reset(); //delay(9000); // test WDT
  current_millis = millis();
  // put your main code here, to run repeatedly:
  flashLed();
  // read sms
  if (((current_millis - timer_read_sms) >= period_read_sms) && (wait_response == 0) && (modem_step == 101)) {
    timer_read_sms = current_millis; // reset timer read sms
    // set mode read sms
    modem_step = 9;
  }
  // send sms
  if (((current_millis - timer_send_sms) >= period_send_sms) && (wait_response == 0) && (modem_step == 101) && (sender[0] > 0) && (sms_buf[0] > 0)) {
    timer_send_sms = current_millis; // reset timer send sms
    // send sms
    modem_step = 11;
  }
  // door control
#ifdef DOOR_CONTROL
  if (READKEY) {
    if (((current_millis - timer_deb_key) >= period_deb_key) && (deviceMode)) {
      if ((!flsend_alarm_door) && (modem_step != 100)) {
        flsend_alarm_door = 1; sendSMS(phoneMain, (char*) "Alarm! Door opened! ");
        timer_alarm_door = current_millis;
      }
    }
  } else {
    timer_deb_key = current_millis;
  }
  if (flsend_alarm_door) if ((current_millis - timer_alarm_door) >= delay_alarm_door) flsend_alarm_door = 0;
#endif
  // external power control
#ifdef EXT_POW_CONTROL
  // power 220V control
  if (startPowerTimer) {
    byte currentPower = READEXTPOW;
    if (lastPower220) {
      if (!currentPower) {
        startPowerTimer = 0; lastPower220 = currentPower;
      } else {
        if ((current_millis - timer_power_on_off) >= delaySMSpowerON) {
          startPowerTimer = 0; sendSMS(phoneMain, (char *) "Power AC220 ON ");
        }
      }
    } else {
      if (currentPower) {
        startPowerTimer = 0; lastPower220 = currentPower;
      } else {
        if ((current_millis - timer_power_on_off) >= delaySMSpowerOFF) {
          startPowerTimer = 0; sendSMS(phoneMain, (char *) "Alarm! Power AC220 OFF ");
        }
      }
    }
  } else {
    if (READEXTPOW != lastPower220) {
      startPowerTimer = 1; timer_power_on_off = current_millis; lastPower220 = READEXTPOW;
    }
  }
#endif
  // get balance
  if ((wait_response == 0) && (modem_step == 101) && (flGetBalance)) {
    flGetBalance = 0; modem_step = 21;
  }
#ifdef USE_DS18B20
  if (((current_millis - timer_get_temp) >= period_get_temp) && (wait_response == 0) && (modem_step == 101)) {
    if (requestTemp) {
      sensors.requestTemperatures(); requestTemp = 0;
    } else if ((current_millis - timer_get_temp) >= (period_get_temp + 200UL)) { // for 9 bit PRECISION
      timer_get_temp = current_millis; requestTemp = 1;
      byte i = 0; while (i < dsCount) {
        float tct = sensors.getTempC(massTherm[i]);
        if (tct < 0) massTemper[i] = ((-tct) * 10) + 2000; else massTemper[i] = (tct * 10);
        ++i;
      }
    }
  }
#endif
  // modem work
  loadDataFromModem(); // load data
  mainLoopModem(); // main actions on modem
}

void initAll() {
#ifdef DOOR_CONTROL
  pinMode(key_pin, INPUT_PULLUP);
  flsend_alarm_door = 0;
  deviceMode = 1;
#endif
#ifdef EXT_POW_CONTROL
  pinMode(ext_pow_pin, INPUT);
  lastPower220 = READEXTPOW; startPowerTimer = 0;
#endif
  pinMode(led1_pin, OUTPUT); LED1OFF;
  pinMode(led2_pin, OUTPUT); LED2OFF;
  pinMode(reset_A6_pin, OUTPUT); pinMode(power_A6_pin, OUTPUT);
  initModem();
  ledError = 1; // 1 = modem status 100
}

void initModem() {
  digitalWrite(reset_A6_pin, LOW);
  digitalWrite(power_A6_pin, HIGH);
  while ((millis() - current_millis) <= 3200UL) {
    Serial.print("AT\r\n"); delay(100);
  }
  modem_step = 100; // first step = wait modem for registration on net
  wait_response = 0; // no wait response
  sms_buf[0] = 0; // clear sms
  sender[0] = 0; // clear sender
  timer_reg_modem = millis(); pos_buf = 0;
  resp_buf[pos_buf] = 0; ledStatus = 0;
  flGetBalance = 0; flag_wait_phone = 0; FirstStart = 1;
}

void resetModem() {
  ledError = 2;
  digitalWrite(reset_A6_pin, HIGH); delay(500);
  initModem();
}

void flashLed() {
  // led1 - led status
  if ((ledStatus > 0) && (ledStatus <= 15)) {
    if ((current_millis - timer_led_status) >= (3000UL + (250UL * flLedSt))) {
      if (flLedSt >= (ledStatus * 2)) {
        LED1OFF; flLedSt = 0; timer_led_status = current_millis;
      } else {
        if (bitRead(flLedSt, 0)) LED1OFF; else LED1ON; ++flLedSt;
      }
    }
  } else {
    LED1OFF;
  }
  // led2 - led error
  switch (ledError) {
    case 1: {
        if ((current_millis - timer_led_error) >= 1000UL) {
          if (flLedEr) {
            if ((current_millis - timer_led_error) >= 1050UL) {
              timer_led_error = current_millis; LED2OFF; flLedEr = 0;
            }
          } else {
            LED2ON; flLedEr = 1;
          }
        }
        break;
      }
    case 2: {
        if ((current_millis - timer_led_error) >= 50UL) {
          if (flLedEr) {
            if ((current_millis - timer_led_error) >= 100UL) {
              timer_led_error = current_millis; LED2OFF; flLedEr = 0;
            }
          } else {
            LED2ON; flLedEr = 1;
          }
        }
        break;
      }
    default: {
        if ((current_millis - timer_led_error) >= 3000UL) {
          if (flLedEr) {
            if ((current_millis - timer_led_error) >= 3050UL) {
              timer_led_error = current_millis; LED2OFF; flLedEr = 0;
            }
          } else {
            LED2ON; flLedEr = 1;
          }
        }
      }
  }
}

const char at0cmd[] PROGMEM = "AT\r\n"; //          0
const char at1cmd[] PROGMEM = "AT+DDET=1\r\n";
const char at2cmd[] PROGMEM = "ATE0\r\n"; //        1
const char at3cmd[] PROGMEM = "AT+CLIP=1\r\n"; //   3
const char at4cmd[] PROGMEM = "ATS0=5\r\n"; //      4
const char at5cmd[] PROGMEM = "ATV1\r\n"; //        2
const char at6cmd[] PROGMEM = "AT+CMEE=2\r\n";
const char at7cmd[] PROGMEM = "AT+CMGF=1\r\n"; //   6
const char at8cmd[] PROGMEM = "AT+CREG?\r\n"; const char at8resp1[] PROGMEM = "+CREG:"; const char at8resp2[] PROGMEM = ",1"; //   5
const char at9cmd[] PROGMEM = "AT+CMGL=\"ALL\"\r\n";
const char at10cmd[] PROGMEM = "AT+CMGD=1,4\r\n"; //   7
const char at11cmd[] PROGMEM = "AT+CMGS=\"";
const char at12cmd[] PROGMEM = "~sender~";
const char at13cmd[] PROGMEM = "\r\n"; const char at13resp1[] PROGMEM = ">";
const char at14cmd[] PROGMEM = "~textsms~";
const char at15cmd[] PROGMEM = "~ctrlz~"; const char at15resp1[] PROGMEM = "+CMGS:";
const char at16cmd[] PROGMEM = "ATA\r\n"; const char at16resp2[] PROGMEM = "NO CARRIER";
const char at17cmd[] PROGMEM = "ATH\r\n";
const char at18cmd[] PROGMEM = "\"";
const char at19cmd[] PROGMEM = "AT+CSQ\r\n"; const char at19resp1[] PROGMEM = "+CSQ:"; const char at19resp2[] PROGMEM = ",";
const char at20cmd[] PROGMEM = "AT+GSN\r\n"; // get imei
const char atOKcmd[] PROGMEM = "OK";
const char atOKRNcmd[] PROGMEM = "OK\r\n";
const char atNULLcmd[] PROGMEM = "";
const char at1status[] PROGMEM = "1";
const char at2status[] PROGMEM = "2";
const char at1step[] PROGMEM = "1"; const char at2step[] PROGMEM = "2"; const char at3step[] PROGMEM = "3"; const char at4step[] PROGMEM = "4";
const char at5step[] PROGMEM = "5"; const char at6step[] PROGMEM = "6"; const char at7step[] PROGMEM = "7"; const char at8step[] PROGMEM = "8";
const char at9step[] PROGMEM = "9"; const char at10step[] PROGMEM = "10"; const char at11step[] PROGMEM = "11"; const char at12step[] PROGMEM = "12";
const char at13step[] PROGMEM = "13"; const char at14step[] PROGMEM = "14"; const char at15step[] PROGMEM = "15"; const char at16step[] PROGMEM = "16";
const char at17step[] PROGMEM = "17"; const char at18step[] PROGMEM = "18"; const char at19step[] PROGMEM = "19"; const char at101step[] PROGMEM = "101";
const char at20step[] PROGMEM = "20";
const char at21resp1[] PROGMEM = "+CUSD: 2,"; const char at21resp2[] PROGMEM = ",72\r\n";

const char * const str_at[] PROGMEM = { // record of AT commands
  at0cmd, atOKcmd, atNULLcmd, atNULLcmd, at1status, at2step,
  at1cmd, atOKcmd, atNULLcmd, atNULLcmd, at1status, at2step,
  at2cmd, atOKcmd, atNULLcmd, atNULLcmd, at1status, at3step,
  at3cmd, atOKcmd, atNULLcmd, atNULLcmd, at1status, at4step,
  at4cmd, atOKcmd, atNULLcmd, atNULLcmd, at1status, at5step,
  at5cmd, atOKcmd, atNULLcmd, atNULLcmd, at1status, at7step,
  at6cmd, atOKcmd, atNULLcmd, atNULLcmd, at1status, at7step,
  at7cmd, atOKcmd, atNULLcmd, atNULLcmd, at1status, at8step,
  at8cmd, at8resp1, at8resp2, atOKcmd, at1status, at20step,
  at9cmd, atOKRNcmd, atNULLcmd, atNULLcmd, at1status, at101step,
  at10cmd, atOKcmd, atNULLcmd, atNULLcmd, at1status, at101step,
  at11cmd, atNULLcmd, atNULLcmd, atNULLcmd, at1status, at12step,
  at12cmd, atNULLcmd, atNULLcmd, atNULLcmd, at1status, at18step,
  at13cmd, at13resp1, atNULLcmd, atNULLcmd, at1status, at14step,
  at14cmd, atNULLcmd, atNULLcmd, atNULLcmd, at1status, at15step,
  at15cmd, at15resp1, atOKcmd, atNULLcmd, at1status, at101step,
  at16cmd, atOKRNcmd, at16resp2, atNULLcmd, at2status, at101step,
  at17cmd, atOKRNcmd, atNULLcmd, atNULLcmd, at1status, at101step,
  at18cmd, atNULLcmd, atNULLcmd, atNULLcmd, at1status, at13step,
  at19cmd, at19resp1, at19resp2, atOKcmd, at1status, at101step,
  at20cmd, atOKcmd, atNULLcmd, atNULLcmd, at1status, at10step, // get imei and go to 10 cmd - last cmd for init - delete sms
  at21cmd, atOKRNcmd, at21resp1, at21resp2, at1status, at101step
};

void getPgmBuf(byte idxPgmBuf) {
  const char * addrStroki = pgm_read_word_near((int)(str_at + idxPgmBuf));
  strcpy_P(pgm_buf, addrStroki);
}

void loadDataFromModem() { // load data from modem to buf - only one line (string)
  if (Serial.available()) {
    byte br;
    while (Serial.available()) {
      br = Serial.read();
      if (br) {
        if (pos_buf >= (max_size_resp_buf - 1)) pos_buf = 0;
        resp_buf[pos_buf] = br; ++pos_buf;
        if (br == '\n') if ((pos_buf > 1) && (resp_buf[pos_buf - 2] == '\r')) break; // new string*/
      }
    }
    resp_buf[pos_buf] = 0; // stop byte of string
  }
}

void mainLoopModem() { // main action modem
  switch (modem_step) {
    case 100: {
        if ((current_millis - timer_reg_modem) >= 20000UL) { // wait 20sec registration modem
          wait_response = 0; // do not response
          modem_step = 0; // go to init modem mode - first command
        }
        break;
      }
    case 101: {
        ledError = 0; ledStatus = 0;
        if (FirstStart) {
          FirstStart = 0;
          flag_wait_phone = 1;
          timer_wait_phone = current_millis;
        }
        if (pos_buf == 0) break; // no response
        // find ring and other commands and execute
        if (flag_wait_phone) {
          if ((current_millis - timer_wait_phone) < period_wait_phone) {
            byte pb1 = posSubStrFromPos(resp_buf, pos_buf, (char *) "+CLIP:", 0);
            if (pb1) {
              byte pb2 = posSubStrFromPos(resp_buf, pos_buf, (char *) "79", 0);
              //--
              if ((pb1) && (pb2 > (pb1 + 5)) && (pos_buf > (pb2 + 12))) {
                // save to EEPROM
                EEPROM.write(pos_eeprom_flag_saved_admin_phone, 139);
                for (byte i = 0; i < 11; ++i) {
                  byte bc = resp_buf[i + pb2 - 1];
                  phoneMain[i] = bc; EEPROM.write(pos_eeprom_admin_phone + i, bc);
                }
                phoneMain[11] = 0; EEPROM.write(pos_eeprom_admin_phone + 11, 0);
                flag_wait_phone = 0;
                wait_response = 0;
                modem_step = 17; // answer on ring 16 or break ring 17
                break;
              }
              //--
            }
          } else {
            flag_wait_phone = 0;
          }
        }
        // other find
        break;
      }
    default: {
        switch (wait_response) {
          case 0: {
              sendAtCommand(modem_step); // send command to modem
              break;
            }
          case 1: {
              if ((current_millis - timer_reg_modem) >= period_fixed_wait) { // if end timer wait response
                resetModem(); // we have problem - no correct response from modem
              } else {
                if (pos_buf == 0) break; // no response
                // action before find response, example long ussd
                if (findRespParts() == 1) { // need fixed response
                  // good response from modem
                  // other action on one item command
                  switch (modem_step) {
                    case 15: { // end send sms
                        sender[0] = 0; sms_buf[0] = 0; // clear sms buf
                        // go to next step
                        wait_response = 0; // do not wait response
                        getPgmBuf(6 * modem_step + 5);
                        modem_step = strToByte(pgm_buf); // to next at command or mode
                        break;
                      }
                    case 9: { // read all sms
                        // find command from sms
                        if (posSubStrFromPos(resp_buf, pos_buf, (char*) "+CMGL: ", 0) > 0) { // we have sms
                          int sbeg = 0;
                          int spos;
lsms1: if (sbeg < pos_buf) {
                            spos = posSubStrFromPos(resp_buf, pos_buf, (char*) "+CMGL: ", sbeg);
                            if (spos > 0) {
                              spos += 7;
                              if (spos < pos_buf) {
                                spos = posSubStrFromPos(resp_buf, pos_buf, phoneMain, spos);
                                if (spos > 0) {
                                  spos += 7;
                                  spos = posSubStrFromPos(resp_buf, pos_buf, (char*) "\r\n", spos);
                                  if (spos > 0) {
                                    ++spos; // begin text sms
                                    byte ends = posSubStrFromPos(resp_buf, pos_buf, (char*) "\r\n", spos); // end text sms
                                    if (ends > 0) {
                                      for (byte i = 0; i < count_ext_commands; ++i) {
                                        getExtBuf(i);
                                        if (posSubStrFromPos(resp_buf, ends, pgm_buf, spos) > 0) {
                                          execExtCmd(i);
                                          break;
                                        }
                                      }
                                      sbeg = ends;
                                      goto lsms1;
                                    }
                                  }
                                }
                              }
                            }
                          }
                          // go to step delete SMS
                          wait_response = 0; // do not wait response
                          modem_step = 10; // step 10
                        } else {
                          // go to next step
                          wait_response = 0; // do not wait response
                          getPgmBuf(6 * modem_step + 5);
                          modem_step = strToByte(pgm_buf); // to next at command or mode
                        }
                        break;
                      }
                    default: {
                        // go to next step
                        wait_response = 0; // do not wait response
                        getPgmBuf(6 * modem_step + 5);
                        modem_step = strToByte(pgm_buf); // to next at command or mode
                      }
                  }
                }
              }
              break;
            }
          case 2: {
              if ((current_millis - timer_reg_modem) >= period_data_wait) { // if end timer wait response
                // no data or no user action
                // exit from command
                // go to next step
                wait_response = 0; // do not wait response
                getPgmBuf(6 * modem_step + 5);
                modem_step = strToByte(pgm_buf); // to next at command or mode
              } else {
                if (pos_buf == 0) break; // no response
                // read parts of sms or other commands or DTMF
                // go to next step after actions
                wait_response = 0; // do not wait response
                getPgmBuf(6 * modem_step + 5);
                modem_step = strToByte(pgm_buf); // to next at command or mode
              }
              break;
            }
          default: {
              // go to next step after actions
              wait_response = 0; // do not wait response
              getPgmBuf(6 * modem_step + 5);
              modem_step = strToByte(pgm_buf); // to next at command or mode
            }
        }
      }
  }
}

int strPos(char *str11, char *str22) { // find position substring in string
  char*p = LastPos(str11, str22);
  int n = p - str11;
  return n;
}

char* LastPos(char *str1, char *str2) { // find substring in string
  int L1 = strlen(str1);
  int L2 = strlen(str2);
  for (int i = L1 - L2; i >= 0; i--)
  {
    int j = 0;
    for (; j < L2; j++)
      if ((str1[i + j] != str2[j]))
        break;
    if (j == L2)
      return str1 + i;
  }
  return 0;
}

void sendAtCommand(byte numcmd) { // send at command if modem not busy
  // find key worlds
  getPgmBuf(6 * numcmd);
  if (posSubStrFromPos(pgm_buf, strlen(pgm_buf), (char *) "~sender~", 0) > 0) {
    Serial.print(sender);
  } else if (posSubStrFromPos(pgm_buf, strlen(pgm_buf), (char *) "~textsms~", 0) > 0) {
    Serial.print(sms_buf);
  } else if (posSubStrFromPos(pgm_buf, strlen(pgm_buf), (char *) "~ctrlz~", 0) > 0) {
    Serial.print(char(26));
  } else {
    Serial.print(pgm_buf); // send cmd from cmd buf by number cmd
  }
  timer_reg_modem = current_millis; // reset wait response timer
  // load response from command to buf
  getPgmBuf(6 * numcmd + 1);
  if (pgm_buf[0] == 0) { // no response
    resp1[0] = 0; resp2[0] = 0; resp3[0] = 0; // no response
    wait_response = 0;
    getPgmBuf(6 * numcmd + 5);
    modem_step = strToByte(pgm_buf); // go to next step or mode
    pos_buf = 0; // clear response buf
    return; // next loop
  } else {
    getPgmBuf(6 * numcmd + 1);
    byte i = 0; while ((resp1[i] = pgm_buf[i]) > 0) ++i; resp1[i] = 0; // save first response from buf at cmd
    getPgmBuf(6 * numcmd + 2);
    if (pgm_buf[0] == 0) { // no second response
      resp2[0] = 0; resp3[0] = 0; // no response 2 and 3
    } else {
      byte i = 0; while ((resp2[i] = pgm_buf[i]) > 0) ++i; resp2[i] = 0; // save secont response from buf at cmd
      getPgmBuf(6 * numcmd + 3);
      if (pgm_buf[0] == 0) { // no thr response
        resp3[0] = 0; // no response 3
      } else {
        byte i = 0; while ((resp3[i] = pgm_buf[i]) > 0) ++i; resp3[i] = 0; // save thr response from buf at cmd
      }
    }
  }
  getPgmBuf(6 * numcmd + 4);
  wait_response = strToByte(pgm_buf); // set wait resp from command buf
  flresp1 = 0; flresp2 = 0; flresp3 = 0; // clear result response
  pos_buf = 0; resp_buf[pos_buf] = 0; // clear response buf
  ledStatus = numcmd + 1; ledError = 0;
}


byte strToByte(char *instr) {
  byte sl = strlen(instr);
  if (sl < 1) return 0;
  byte res = 0, i = 0;
  while (instr[i] > 0) {
    res += ((instr[i] - '0') * pow(10, (sl - i - 1)));
    ++i;
  }
  if (sl > 2) ++res;
  return res;
}

byte posSubStrFromPos(char *inBuf, byte maxPosBuf, char *subStr, byte resPos) {
  if (resPos >= maxPosBuf) return 0;
  while ((resPos < maxPosBuf) && (inBuf[resPos] > 0)) {
    byte isub = 0;
    if (inBuf[resPos] == subStr[isub]) {
      byte sslen = strlen(subStr);
      while (((resPos + isub) < maxPosBuf) && (inBuf[resPos + isub] > 0) && (isub < sslen)) {
        if (subStr[isub] != inBuf[resPos + isub]) break;
        ++isub;
      }
      if (isub >= sslen)   {
        ++resPos;
        return resPos;
      }
    }
    ++resPos;
  }
  return 0;
}

byte findRespParts() { // find response parts in response buf
  byte countresp = 0, countgood = 0;
  if (resp1[0] > 0) { // exist response 1
    ++countresp;
    if (strPos(resp_buf, resp1) >= 0) {
      flresp1 = 1; // found response 1
    }
    if (resp2[0] > 0) { // exist response 2
      ++countresp;
      if (strPos(resp_buf, resp2 ) >= 0) {
        flresp2 = 1; // found response 2
      }
      if (resp3[0] > 0) { // exist response 3
        ++countresp;
        if (strPos(resp_buf, resp3) >= 0) {
          flresp3 = 1; // found response 3
        }
      }
    }
  }
  if (flresp1 == 1) {
    ++countgood;
  }
  if (flresp2 == 1) {
    ++countgood;
  }
  if (flresp3 == 1) {
    ++countgood; // calculate good response
  }
  if ((countresp > 0) && (countresp == countgood)) return 1; else return 0;
}

const char ex0cmd[] PROGMEM = "getstatus"; const char ex1cmd[] PROGMEM = "poweroff"; const char ex2cmd[] PROGMEM = "poweron";
const char ex3cmd[] PROGMEM = "getbalance";

const char * const ext_pgm_cmd[] PROGMEM = {
  ex0cmd, ex1cmd, ex2cmd, ex3cmd
};

void getExtBuf(byte idxPgmBuf) {
  const char * addrStroki = pgm_read_word_near((int)(ext_pgm_cmd + idxPgmBuf));
  strcpy_P(pgm_buf, addrStroki);
}

void execExtCmd(byte numCmd) {
  switch (numCmd) {
    case 0: {
#ifdef DOOR_CONTROL
        if (deviceMode) sendSMS(phoneMain, (char*) "Power ON "); else sendSMS(phoneMain, (char*) "Power OFF ");
#endif
        break;
      }
    case 1: {
#ifdef DOOR_CONTROL
        deviceMode = 0;
#endif
        break;
      }
    case 2: {
#ifdef DOOR_CONTROL
        deviceMode = 1;
#endif
        break;
      }
    case 3: {
        flGetBalance = 1;
        break;
      }
    default: {}
  }
}

void sendSMS(char *phnum, char *txtsms) { // prepare sender phone number and text for sms
  sender[0] = 0;
  sms_buf[0] = 0;
  strcpy(sender, "+"); strcat(sender, phnum);
  strcpy(sms_buf, txtsms);
  byte i = strlen(sms_buf);
  i = addTextUptime(sms_buf, i , max_size_sms_buf); // add uptime text to sms buf
  sms_buf[i] = 0;
#ifdef USE_DS18B20
  if (dsCount) {
    i = addTextTemp0(sms_buf, i , max_size_sms_buf); // add DS18B20 temp idx 0 to sms buf
    sms_buf[i] = 0;
  }
#endif
  timer_send_sms = current_millis; // reset timer send sms
  timer_read_sms = current_millis; // reset timer read sms
}

byte addTextUptime(char *text, byte firstpos, byte maxsize) { // add uptime text to input text
  byte days = current_millis / 86400000UL;
  byte hours = (current_millis % 86400000UL) / 3600000UL;
  byte mins = ((current_millis % 86400000UL) % 3600000UL) / 60000UL;
  if (firstpos >= (maxsize - 1)) return firstpos;
  text[firstpos] = 'u'; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
  if (days > 9) {
    text[firstpos] = (days / 10) + '0'; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
  }
  text[firstpos] = (days % 10) + '0'; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
  text[firstpos] = 'd'; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
  if (hours > 9) {
    text[firstpos] = (hours / 10) + '0'; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
  }
  text[firstpos] = (hours % 10) + '0'; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
  text[firstpos] = 'h'; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
  if (mins > 9) {
    text[firstpos] = (mins / 10) + '0'; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
  }
  text[firstpos] = (mins % 10) + '0'; ++firstpos;  if (firstpos >= (maxsize - 1)) return firstpos;
  text[firstpos] = 'm'; ++firstpos;
  return firstpos;
}

byte addTextTemp0(char *text, byte firstpos, byte maxsize) { // add uptime text to input text
  if (firstpos >= (maxsize - 1)) return firstpos;
  text[firstpos] = ' '; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
  word ttt = massTemper[0];
  if (ttt >= 2000) {
    text[firstpos] = '-'; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
    ttt -= 2000;
  }
  word bbb = ttt / 10;
  if (bbb > 9) {
    text[firstpos] = (bbb / 10) + '0'; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
  }
  text[firstpos] = (bbb % 10) + '0'; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
  text[firstpos] = '.'; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
  text[firstpos] = (ttt % 10) + '0'; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
  text[firstpos] = ' '; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
  text[firstpos] = '\''; ++firstpos; if (firstpos >= (maxsize - 1)) return firstpos;
  text[firstpos] = 'C'; ++firstpos;
  return firstpos;
}

 

 

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

за пайку - жырную два. 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

DetSimen пишет:

за пайку - жырную два. 

а где там наверху видно какая пайка? ;) - максимум расположение элементов.

ну а так да......стыдно. Ну не серийное же устройство делаю.

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

andycat пишет:

ну а так да......стыдно. 

Да я пашутил же, намайная пайка, просто я ненавижу хитросплетения торчащих какпапало проводов. 

Посоветуй лучше, где брал держатели для 18650?  Где не находил, выходят 145р с пересылкой, а у мня на такие деньжищщи - амфибиотропная асфиксия. 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

https://ru.aliexpress.com/item/32841386302.html

аналогично дорого :( доставка

да еще и долго - 1.5 месяца

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

лана. будем копить. :) 

бутылки хоть сдам, в канцеканцов.