bool CompositeCommandsModule::ExecCommand(const Command& command, bool wantAnswer) { if(wantAnswer) PublishSingleton = UNKNOWN_COMMAND; size_t argsCount = command.GetArgsCount(); if(command.GetType() == ctGET) { if(wantAnswer) PublishSingleton = NOT_SUPPORTED; } else if(command.GetType() == ctSET) { if(argsCount < 1) { PublishSingleton = PARAMS_MISSED; } else { // есть параметры String which = command.GetArg(0); if(which == CC_DELETE_COMMAND) // очистить все команды { Clear(); if(wantAnswer) PublishSingleton = REG_DEL; // говорим, что удалили всё PublishSingleton.Status = true; } // CC_DELETE_COMMAND else if(which == CC_SAVE_COMMAND) // сохранить команды в EEPROM { SaveCommands(); if(wantAnswer) PublishSingleton = REG_SUCC; // говорим, что сохранили PublishSingleton.Status = true; } // CC_SAVE_COMMAND else if(which == CC_PROCESS_COMMAND) // выполнить команду { if(argsCount > 1) { // хватает аргументов uint8_t cmd = abs(atoi(command.GetArg(1))); ProcessCommand(cmd); // выполняем составную команду if(wantAnswer) PublishSingleton = REG_SUCC; // говорим, что выполнили PublishSingleton.Status = true; } else { // не хватает аргументов if(wantAnswer) PublishSingleton = PARAMS_MISSED; } } // CC_PROCESS_COMMAND else if(which == CC_ADD_COMMAND) // добавить параметр в список составной команды { if(argsCount > 3) { uint8_t listIdx = abs(atoi(command.GetArg(1))); uint8_t action = abs(atoi(command.GetArg(2))); uint8_t param = abs(atoi(command.GetArg(3))); AddCommand(listIdx,action,param); // добавляем команду if(wantAnswer) PublishSingleton = REG_SUCC; // говорим, что добавили PublishSingleton.Status = true; } else { // не хватает аргументов if(wantAnswer) PublishSingleton = PARAMS_MISSED; } } // CC_ADD_COMMAND } // else } // ctSET // отвечаем на команду MainController->Publish(this,command); return PublishSingleton.Status; }
bool ZeroStreamListener::ExecCommand(const Command& command, bool wantAnswer) { if(wantAnswer) PublishSingleton = UNKNOWN_COMMAND; bool canPublish = true; // флаг, что можем публиковать size_t argsCnt = command.GetArgsCount(); if(command.GetType() == ctGET) { PublishSingleton = NOT_SUPPORTED; if(!argsCnt) // нет аргументов { PublishSingleton = PARAMS_MISSED; } else { if(argsCnt < 1) { // мало параметров PublishSingleton = PARAMS_MISSED; } // if else { String t = command.GetArg(0); // получили команду t.toUpperCase(); if(t == PING_COMMAND) // пинг { PublishSingleton.Status = true; PublishSingleton = PONG; PublishSingleton.AddModuleIDToAnswer = false; } // if else if(t == UNI_RF_CHANNEL_COMMAND) { PublishSingleton.Status = true; PublishSingleton = UNI_RF_CHANNEL_COMMAND; PublishSingleton << PARAM_DELIMITER; PublishSingleton << UniDispatcher.GetRFChannel(); PublishSingleton.AddModuleIDToAnswer = false; } #if defined(USE_UNIVERSAL_SENSORS) && defined(UNI_USE_REGISTRATION_LINE) else if(t == UNI_SEARCH) // поиск универсального модуля на линии регистрации { PublishSingleton.AddModuleIDToAnswer = false; if(uniRegistrator.IsModulePresent()) { // датчик найден, отправляем его внутреннее состояние PublishSingleton.Status = true; UniRawScratchpad scratch; uniRegistrator.CopyScratchpad(&scratch); byte* raw = (byte*) &scratch; PublishSingleton = ""; // теперь пишем весь скратчпад вызывающему, пущай сам разбирается, как с ним быть for(byte i=0;i<sizeof(UniRawScratchpad);i++) { PublishSingleton << WorkStatus::ToHex(raw[i]); } // for } // if else { // датчика нету PublishSingleton = UNI_NOT_FOUND; } // else } #endif // UNI_USE_REGISTRATION_LINE else if(t == ID_COMMAND) { PublishSingleton.Status = true; PublishSingleton.AddModuleIDToAnswer = false; PublishSingleton = ID_COMMAND; PublishSingleton << PARAM_DELIMITER << MainController->GetSettings()->GetControllerID(); } else if(t == WIRED_COMMAND) // получить количество жёстко указанных в прошивке обычных датчиков { PublishSingleton.Status = true; PublishSingleton.AddModuleIDToAnswer = false; PublishSingleton = WIRED_COMMAND; PublishSingleton << PARAM_DELIMITER << UniDispatcher.GetHardCodedSensorsCount(uniTemp); PublishSingleton << PARAM_DELIMITER << UniDispatcher.GetHardCodedSensorsCount(uniHumidity); PublishSingleton << PARAM_DELIMITER << UniDispatcher.GetHardCodedSensorsCount(uniLuminosity); PublishSingleton << PARAM_DELIMITER << UniDispatcher.GetHardCodedSensorsCount(uniSoilMoisture); PublishSingleton << PARAM_DELIMITER << UniDispatcher.GetHardCodedSensorsCount(uniPH); //TODO: Тут остальные типы датчиков указывать !!! } else if(t == UNI_COUNT_COMMAND) // получить количество зарегистрированных универсальных датчиков { PublishSingleton.Status = true; PublishSingleton.AddModuleIDToAnswer = false; PublishSingleton = UNI_COUNT_COMMAND; PublishSingleton << PARAM_DELIMITER << UniDispatcher.GetUniSensorsCount(uniTemp); PublishSingleton << PARAM_DELIMITER << UniDispatcher.GetUniSensorsCount(uniHumidity); PublishSingleton << PARAM_DELIMITER << UniDispatcher.GetUniSensorsCount(uniLuminosity); PublishSingleton << PARAM_DELIMITER << UniDispatcher.GetUniSensorsCount(uniSoilMoisture); PublishSingleton << PARAM_DELIMITER << UniDispatcher.GetUniSensorsCount(uniPH); //TODO: Тут остальные типы датчиков указывать !!! } else if(t == SMS_NUMBER_COMMAND) // номер телефона для управления по СМС { PublishSingleton.Status = true; PublishSingleton.AddModuleIDToAnswer = false; PublishSingleton = SMS_NUMBER_COMMAND; PublishSingleton << PARAM_DELIMITER << MainController->GetSettings()->GetSmsPhoneNumber(); } else if(t == STATUS_COMMAND) // получить статус всего железного добра { if(wantAnswer) { // входящий поток установлен, значит, можем писать прямо в него canPublish = false; // скажем, что мы не хотим публиковать через контроллер - будем писать в поток сами Stream* pStream = command.GetIncomingStream(); pStream->print(OK_ANSWER); pStream->print(COMMAND_DELIMITER); WORK_STATUS.WriteStatus(pStream,true); // просим записать статус // тут можем писать остальные статусы, типа показаний датчиков и т.п.: size_t modulesCount = MainController->GetModulesCount(); // получаем кол-во зарегистрированных модулей // const char* noDataByte = "FF"; // байт - нет данных с датчика // пробегаем по всем модулям String moduleName; moduleName.reserve(20); for(size_t i=0;i<modulesCount;i++) { yield(); // немного даём поработать другим модулям AbstractModule* mod = MainController->GetModule(i); // if(mod == this) // себя пропускаем // continue; // проверяем, не пустой ли модуль. для этого смотрим, сколько у него датчиков вообще uint8_t tempCount = mod->State.GetStateCount(StateTemperature); uint8_t humCount = mod->State.GetStateCount(StateHumidity); uint8_t lightCount = mod->State.GetStateCount(StateLuminosity); uint8_t waterflowCountInstant = mod->State.GetStateCount(StateWaterFlowInstant); uint8_t waterflowCount = mod->State.GetStateCount(StateWaterFlowIncremental); uint8_t soilMoistureCount = mod->State.GetStateCount(StateSoilMoisture); uint8_t phCount = mod->State.GetStateCount(StatePH); //TODO: тут другие типы датчиков!!! if((tempCount + humCount + lightCount + waterflowCountInstant + waterflowCount + soilMoistureCount + phCount) < 1) // пустой модуль, без интересующих нас датчиков continue; uint8_t flags = 0; if(tempCount) flags |= StateTemperature; if(humCount) flags |= StateHumidity; if(lightCount) flags |= StateLuminosity; if(waterflowCountInstant) flags |= StateWaterFlowInstant; if(waterflowCount) flags |= StateWaterFlowIncremental; if(soilMoistureCount) flags |= StateSoilMoisture; if(phCount) flags |= StatePH; //TODO: Тут другие типы датчиков!!! // показание каждого модуля идут так: // 1 байт - флаги о том, какие датчики есть pStream->write(WorkStatus::ToHex(flags)); // 1 байт - длина ID модуля moduleName = mod->GetID(); uint8_t mnamelen = moduleName.length(); pStream->write(WorkStatus::ToHex(mnamelen)); // далее идёт имя модуля pStream->write(moduleName.c_str()); // затем идут данные из модуля, сначала - показания температуры, если они есть PrintSensorsValues(tempCount,StateTemperature,mod,pStream); // затем идёт кол-во датчиков влажности, если они есть PrintSensorsValues(humCount,StateHumidity,mod,pStream); // затем идут показания датчиков освещенности, если они есть PrintSensorsValues(lightCount,StateLuminosity,mod,pStream); // затем идут моментальные показания датчиков расхода воды, если они есть PrintSensorsValues(waterflowCountInstant,StateWaterFlowInstant,mod,pStream); // затем идут накопительные показания датчиков расхода воды, если они есть PrintSensorsValues(waterflowCount,StateWaterFlowIncremental,mod,pStream); // затем идут датчики влажности почвы, если они есть PrintSensorsValues(soilMoistureCount,StateSoilMoisture,mod,pStream); // затем идут датчики pH, если они есть PrintSensorsValues(phCount,StatePH,mod,pStream); //TODO: тут другие типы датчиков!!! } // for pStream->print(NEWLINE); // пишем перевод строки } // wantAnswer } // STATUS_COMMAND else if(t == REGISTERED_MODULES_COMMAND) // пролистать зарегистрированные модули { PublishSingleton.AddModuleIDToAnswer = false; PublishSingleton.Status = true; PublishSingleton = F(""); size_t cnt = MainController->GetModulesCount(); for(size_t i=0;i<cnt;i++) { AbstractModule* mod = MainController->GetModule(i); if(mod != this) { if(PublishSingleton.Text.length()) PublishSingleton << PARAM_DELIMITER; PublishSingleton << mod->GetID(); }// if } // for } else { // неизвестная команда } // else } // else } // elsse } // ctGET else if(command.GetType() == ctSET) { if(!argsCnt) // нет аргументов { PublishSingleton = PARAMS_MISSED; } else { if(argsCnt < 2) { // мало параметров PublishSingleton = PARAMS_MISSED; String t = command.GetArg(0); if(t == RESET_COMMAND) { resetFunc(); // ресетимся, писать в ответ ничего не надо } // RESET_COMMAND else if(t == F("AUTO")) // CTSET=0|AUTO - перевести в автоматический режим { // очищаем общий буфер ответов PublishSingleton = ""; // выполняем команды ModuleInterop.QueryCommand(ctSET, F("STATE|MODE|AUTO"),false,false); ModuleInterop.QueryCommand(ctSET, F("WATER|MODE|AUTO"),false,false); ModuleInterop.QueryCommand(ctSET, F("LIGHT|MODE|AUTO"),false,false); // говорим, что выполнили PublishSingleton = REG_SUCC; PublishSingleton.Status = true; } // AUTO } // if else { String t = command.GetArg(0); // получили команду #ifdef USE_REMOTE_MODULES if(t == ADD_COMMAND) // запросили регистрацию нового модуля { // ищем уже зарегистрированный String reqID = command.GetArg(1); AbstractModule* mod = c->GetModuleByID(reqID); if(mod) { // модуль уже зарегистрирован PublishSingleton = REG_ERR; PublishSingleton << PARAM_DELIMITER << reqID; } // if else { // регистрируем новый модуль RemoteModule* remMod = new RemoteModule(reqID); c->RegisterModule(remMod); PublishSingleton.Status = true; PublishSingleton = REG_SUCC; PublishSingleton << PARAM_DELIMITER << reqID; } // else } else #endif if(t == SMS_NUMBER_COMMAND) // номер телефона для управления по SMS { GlobalSettings* sett = MainController->GetSettings(); sett->SetSmsPhoneNumber(command.GetArg(1)); sett->Save(); PublishSingleton.Status = true; PublishSingleton = SMS_NUMBER_COMMAND; PublishSingleton << PARAM_DELIMITER << REG_SUCC; } else if(t == UNI_RF_CHANNEL_COMMAND) { byte ch = atoi(command.GetArg(1)); UniDispatcher.SetRFChannel(ch); #ifdef USE_NRF_GATE nrfGate.SetChannel(ch); #endif PublishSingleton.Status = true; PublishSingleton = UNI_RF_CHANNEL_COMMAND; PublishSingleton << PARAM_DELIMITER << REG_SUCC; } #if defined(USE_UNIVERSAL_SENSORS) && defined(UNI_USE_REGISTRATION_LINE) else if(t == UNI_REGISTER) // зарегистрировать универсальный модуль, висящий на линии { PublishSingleton.AddModuleIDToAnswer = false; if(uniRegistrator.IsModulePresent()) { // модуль есть на линии, регистрируем его в системе. // сначала вычитываем переданный скратчпад и назначаем его модулю. // считаем, что на вызывающей стороне разобрались, что с чем, с остальным // разберётся модуль регистрации. const char* scratchData = command.GetArg(1); // теперь конвертируем данные скратчпада из текстового представления в нормальное char buff[3] = {0}; uint8_t len = strlen(scratchData); UniRawScratchpad scratch; byte* raw = (byte* )&scratch; for(uint8_t i=0;i<len;i+=2) { buff[0] = scratchData[i]; buff[1] = scratchData[i+1]; *raw = WorkStatus::FromHex(buff); raw++; } // for if(uniRegistrator.SetScratchpadData(&scratch)) { uniRegistrator.Register(); PublishSingleton.Status = true; PublishSingleton = REG_SUCC; } // if else { // разные типы скратчпадов, возможно, подсоединили другой модуль PublishSingleton = UNI_DIFFERENT_SCRATCHPAD; } } // if else { // модуля нет на линии PublishSingleton = UNI_NOT_FOUND; } } // UNI_REGISTER #endif // UNI_USE_REGISTRATION_LINE else if(t == ID_COMMAND) { //String newID = command.GetArg(1); MainController->GetSettings()->SetControllerID((uint8_t)atoi(command.GetArg(1))); PublishSingleton.Status = true; PublishSingleton = ID_COMMAND; PublishSingleton << PARAM_DELIMITER << REG_SUCC; } #ifdef USE_DS3231_REALTIME_CLOCK else if(t == SETTIME_COMMAND) { // установка даты/времени String rawDatetime = command.GetArg(1); int8_t idx = rawDatetime.indexOf(F(" ")); String tm, dt; if(idx != -1) { dt = rawDatetime.substring(0,idx); tm = rawDatetime.substring(idx+1); String month,day,year; String hour,minute,sec; idx = dt.indexOf(F(".")); if(idx != -1) { day = dt.substring(0,idx); dt = dt.substring(idx+1); } idx = dt.indexOf(F(".")); if(idx != -1) { month = dt.substring(0,idx); year = dt.substring(idx+1); } idx = tm.indexOf(F(":")); if(idx != -1) { hour = tm.substring(0,idx); tm = tm.substring(idx+1); } idx = tm.indexOf(F(":")); if(idx != -1) { minute = tm.substring(0,idx); sec = tm.substring(idx+1); } // вычисляем день недели int yearint = year.toInt(); int monthint = month.toInt(); int dayint = day.toInt(); int dow; byte mArr[12] = {6,2,2,5,0,3,5,1,4,6,2,4}; dow = (yearint % 100); dow = dow*1.25; dow += dayint; dow += mArr[monthint-1]; if (((yearint % 4)==0) && (monthint<3)) dow -= 1; while (dow>7) dow -= 7; DS3231Clock cl = MainController->GetClock(); cl.setTime(sec.toInt(),minute.toInt(),hour.toInt(),dow,dayint,monthint,yearint); PublishSingleton.Status = true; PublishSingleton = REG_SUCC; } // if } #endif else { // неизвестная команда } // else } // else argsCount > 1 } // else } // if // отвечаем на команду if(canPublish) // можем публиковать MainController->Publish(this,command); else PublishSingleton = F(""); // просто очищаем общий буфер return PublishSingleton.Status; }
bool SoilMoistureModule::ExecCommand(const Command& command, bool wantAnswer) { if(wantAnswer) PublishSingleton = NOT_SUPPORTED; if(command.GetType() == ctSET) // установка свойств { } // ctSET else if(command.GetType() == ctGET) // запрос свойств { uint8_t argsCnt = command.GetArgsCount(); if(argsCnt < 1) { if(wantAnswer) PublishSingleton = PARAMS_MISSED; // не хватает параметров } // argsCnt < 1 else { String param = command.GetArg(0); if(param == ALL) // запросили показания со всех датчиков: CTGET=SOIL|ALL { PublishSingleton.Status = true; uint8_t _cnt = State.GetStateCount(StateSoilMoisture); if(wantAnswer) PublishSingleton = _cnt; for(uint8_t i=0;i<_cnt;i++) { OneState* stateHumidity = State.GetStateByOrder(StateSoilMoisture,i); if(stateHumidity) { HumidityPair hp = *stateHumidity; if(wantAnswer) { PublishSingleton << PARAM_DELIMITER << (hp.Current); } } // if } // for } // param == ALL else if(param == PROP_CNT) // запросили данные о кол-ве датчиков: CTGET=SOIL|CNT { PublishSingleton.Status = true; if(wantAnswer) { PublishSingleton = PROP_CNT; uint8_t _cnt = State.GetStateCount(StateSoilMoisture); PublishSingleton << PARAM_DELIMITER << _cnt; } } // PROP_CNT else if(param != GetID()) // если только не запросили без параметров { // запросили показания с датчика по индексу uint8_t idx = param.toInt(); uint8_t _cnt = State.GetStateCount(StateSoilMoisture); if(idx >= _cnt) { // плохой индекс if(wantAnswer) PublishSingleton = NOT_SUPPORTED; } // плохой индекс else { if(wantAnswer) PublishSingleton = param; OneState* stateHumidity = State.GetStateByOrder(StateSoilMoisture,idx); if(stateHumidity) { PublishSingleton.Status = true; HumidityPair hp = *stateHumidity; if(wantAnswer) { PublishSingleton << PARAM_DELIMITER << (hp.Current); } } // if } // else нормальный индекс } // if param != GetID() } // else } MainController->Publish(this,command); return true; }
//------------------------------------------------------------------------------------------------------------------------------------------------------- bool PhModule::ExecCommand(const Command& command, bool wantAnswer) { if(wantAnswer) PublishSingleton = NOT_SUPPORTED; uint8_t argsCnt = command.GetArgsCount(); if(command.GetType() == ctSET) // установка свойств { if(argsCnt < 1) { if(wantAnswer) PublishSingleton = PARAMS_MISSED; } else { String param = command.GetArg(0); if(param == PH_SETTINGS_COMMAND) // установить настройки: CTSET=PH|T_SETT|calibration_factor|ph4Voltage|ph7Voltage|ph10Voltage|temp_sensor_index|samples_temp|ph_target|ph_histeresis|mix_time|reagent_time { if(argsCnt < 11) { if(wantAnswer) PublishSingleton = PARAMS_MISSED; } else { // аргументов хватает calibration = atoi(command.GetArg(1)); ph4Voltage = atoi(command.GetArg(2)); ph7Voltage = atoi(command.GetArg(3)); ph10Voltage = atoi(command.GetArg(4)); phTemperatureSensorIndex = atoi(command.GetArg(5)); int samplesTemp = atoi(command.GetArg(6)); phSamplesTemperature.Value = samplesTemp/100; phSamplesTemperature.Fract = samplesTemp%100; phTarget = atoi(command.GetArg(7)); phHisteresis = atoi(command.GetArg(8)); phMixPumpTime = atoi(command.GetArg(9)); phReagentPumpTime = atoi(command.GetArg(10)); SaveSettings(); PublishSingleton.Status = true; PublishSingleton = REG_SUCC; } } // PH_SETTINGS_COMMAND } // else argsCount >= 1 } // ctSET else if(command.GetType() == ctGET) // запрос свойств { if(argsCnt < 1) { if(wantAnswer) PublishSingleton = PARAMS_MISSED; // не хватает параметров } // argsCnt < 1 else { String param = command.GetArg(0); if(param == ALL) // запросили показания со всех датчиков: CTGET=PH|ALL { PublishSingleton.Status = true; uint8_t _cnt = State.GetStateCount(StatePH); if(wantAnswer) PublishSingleton = _cnt; for(uint8_t i=0;i<_cnt;i++) { OneState* stateHumidity = State.GetStateByOrder(StatePH,i); if(stateHumidity) { HumidityPair hp = *stateHumidity; if(wantAnswer) { PublishSingleton << PARAM_DELIMITER << (hp.Current); } } // if } // for } // param == ALL else if(param == PH_SETTINGS_COMMAND) // получить/установить настройки: CTGET=PH|T_SETT, CTSET=PH|T_SETT|calibration_factor|ph4Voltage|ph7Voltage|ph10Voltage|temp_sensor_index|samples_temp|ph_target|ph_histeresis|mix_time|reagent_time { PublishSingleton.Status = true; if(wantAnswer) { PublishSingleton = PH_SETTINGS_COMMAND; PublishSingleton << PARAM_DELIMITER << calibration; PublishSingleton << PARAM_DELIMITER << ph4Voltage; PublishSingleton << PARAM_DELIMITER << ph7Voltage; PublishSingleton << PARAM_DELIMITER << ph10Voltage; PublishSingleton << PARAM_DELIMITER << phTemperatureSensorIndex; PublishSingleton << PARAM_DELIMITER << phSamplesTemperature; PublishSingleton << PARAM_DELIMITER << phTarget; PublishSingleton << PARAM_DELIMITER << phHisteresis; PublishSingleton << PARAM_DELIMITER << phMixPumpTime; PublishSingleton << PARAM_DELIMITER << phReagentPumpTime; } } // PH_SETTINGS_COMMAND else if(param == PROP_CNT) // запросили данные о кол-ве датчиков: CTGET=PH|CNT { PublishSingleton.Status = true; if(wantAnswer) { PublishSingleton = PROP_CNT; uint8_t _cnt = State.GetStateCount(StatePH); PublishSingleton << PARAM_DELIMITER << _cnt; } } // PROP_CNT else if(param != GetID()) // если только не запросили без параметров { // запросили показания с датчика по индексу uint8_t idx = param.toInt(); uint8_t _cnt = State.GetStateCount(StatePH); if(idx >= _cnt) { // плохой индекс if(wantAnswer) PublishSingleton = NOT_SUPPORTED; } // плохой индекс else { if(wantAnswer) PublishSingleton = param; OneState* stateHumidity = State.GetStateByOrder(StatePH,idx); if(stateHumidity) { PublishSingleton.Status = true; HumidityPair hp = *stateHumidity; if(wantAnswer) { PublishSingleton << PARAM_DELIMITER << (hp.Current); } } // if } // else нормальный индекс } // if param != GetID() } // else } MainController->Publish(this,command); return true; }