#include "OneButton.h"
#include "FS.h"
#include <LittleFS.h>
#include <ArduinoJson.h>
#define BANKSNUM 5
#define BTNSNUM 5
char * configFile = "/config.json";//配置文件
int currentBTN = 0;//当前的踩钉(保存到文件中下次开机加载)
int programBTN = -1;//被编程的踩钉
int BTNS[] = {4,5,6,7,15};//踩钉
int BTNSTATUS[] = {46,9,10,11,12};//踩钉状态灯
int RELAYS[] = {16,17,18,8,3};//继电器
//int BTNS[] = {25,33,32,35,34};//模拟器
//int BTNSTATUS[] = {13,12,14,27,26};;//模拟器
//int RELAYS[] = {15,2,0,4,17};//模拟器
int RELAYSTATUS[] = {0, 0, 0, 0, 0};//继电器状态灯
int BANKSDEFAULT[BANKSNUM][BTNSNUM] = {//定义默认组
{1, 0, 0, 0, 0},
{0, 1, 0, 0, 0},
{0, 0, 1, 0, 0},
{0, 0, 0, 1, 0},
{0, 0, 0, 0, 5}
};
int BANKS[BANKSNUM][BTNSNUM];
OneButton OBTNS[BTNSNUM];//踩钉对象数组
//输出日志
void logs(char* message, int btn=0, boolean error=false){
if(error){
Serial.print("ERROR:");
Serial.println(message);
}else{
Serial.print("LOG:");
Serial.println(message);
}
}
//切换踩钉状态灯
void lightLED(int btn){
for (int i=0; i<BTNSNUM; i++){
if (btn == i){
digitalWrite(BTNSTATUS[i], HIGH);
}else{
digitalWrite(BTNSTATUS[i], LOW);
}
}
}
//单击切换
void loadClick(int btn){
logs("Load Click", btn);
for (int i=0; i<BTNSNUM; i++){
digitalWrite(RELAYS[i], BANKS[btn][i]);
}
lightLED(btn);//点亮踩钉状态灯
currentBTN = btn;
}
//进入编程
void enterProgram(int btn){
logs("Enter Program", btn);
programBTN = btn;
for (int i=0; i<BTNSNUM; i++){
digitalWrite(RELAYS[i], LOW);//初始化RELAY为0
RELAYSTATUS[i] = 0;//初始化RELAY状态为0
BANKS[programBTN][i] = 0;//初始化BANK为0
}
lightLED(btn);//点亮踩钉状态灯
}
//编程中
void inProgram(int btn){
logs("In Program", btn);
for (int i=0; i<BTNSNUM; i++){
OBTNS[i].reset();
OBTNS[i].attachClick([](void* p){setClick((int)p);}, (void*)i);//监听单击
OBTNS[i].attachDoubleClick([](void* p){exitProgram((int)p);}, (void*)i);//监听双击
OBTNS[i].attachLongPressStart([](void* p){}, (void*)i); //取消监听长按(按下)
OBTNS[i].attachLongPressStop([](void* p){}, (void*)i); //取消监听长按(抬起)
}
}
//编程单击
void setClick(int btn){
logs("Set Click", btn);
if (programBTN != -1){
BANKS[programBTN][btn] = 1;
RELAYSTATUS[btn] = !RELAYSTATUS[btn];
digitalWrite(RELAYS[btn], RELAYSTATUS[btn]);
}
}
//退出编程
void exitProgram(int btn){
logs("Exit Program", btn);
programBTN = -1;
for (int i=0; i<BTNSNUM; i++){
//OBTNS[i] = OneButton(BTNS[i], false, false);
OBTNS[i].reset();
OBTNS[i].attachClick([](void* p){loadClick((int)p);}, (void*)i);//监听单击
OBTNS[i].attachLongPressStart([](void* p){enterProgram((int)p);}, (void*)i);//监听长按(按下)
OBTNS[i].attachLongPressStop([](void* p){inProgram((int)p);}, (void*)i);//监听长按(抬起)
}
}
//保存配置
void saveConfig(){
logs("Writing File");
File file = LittleFS.open(configFile, FILE_WRITE);
if (!file){
logs("Failed to open file for writing", true);
return;
}
JsonDocument doc;
for(int i=0; i<BANKSNUM; i++){
for(int j=0; j<BTNSNUM; j++){
doc["BANKS"][i][j] = BANKS[i][j];
}
}
doc["currentBTN"] = currentBTN;
int size = serializeJson(doc, file);//写入JSON
if (size > 0){
logs("File written success");
}else{
logs("File write failed", true);
}
file.close();
}
//加载配置
void loadConfig(){
logs("Reading File");
File file = LittleFS.open(configFile);
if (!file){
logs("Failed to open file for reading", true);
return;
}
JsonDocument doc;
DeserializationError error = deserializeJson(doc, file);//读取JSON
if (error){
logs("Failed to deserialize json", true);
return;
}
serializeJson(doc, Serial);
for(int i=0; i<BANKSNUM; i++){
for(int j=0; j<BTNSNUM; j++){
BANKS[i][j] = (int)doc["BANKS"][i][j];
}
}
currentBTN = (int)doc["currentBTN"];
file.close();
}
//连击
void multiClick(int btn) {
int count = OBTNS[btn].getNumberClicks();
if (count == 5){
logs("Saving Config");
saveConfig();
}else if (count == 9){
logs("Factory Reset");
memcpy(BANKS, BANKSDEFAULT, sizeof(BANKSDEFAULT));
currentBTN = 0;
saveConfig();
logs("ESP Restarting");
ESP.restart();
}
}
void setup(){
Serial.begin(115200);
logs("Hello, ESP32!");
for (int i=0; i<BTNSNUM; i++){
pinMode(RELAYS[i], OUTPUT);//初始化继电器为输出
pinMode(BTNSTATUS[i], OUTPUT);//初始化踩钉状态灯为输出
pinMode(BTNS[i], INPUT);//初始化踩钉为输入
OBTNS[i] = OneButton(BTNS[i], false, false);//初始化踩钉类
OBTNS[i].reset();
OBTNS[i].attachClick([](void* p){loadClick((int)p);}, (void*)i);//监听单击
OBTNS[i].attachLongPressStart([](void* p){enterProgram((int)p);}, (void*)i);//监听长按(按下)
OBTNS[i].attachLongPressStop([](void* p){inProgram((int)p);}, (void*)i);//监听长按(抬起)
OBTNS[i].attachMultiClick([](void* p){multiClick((int)p);}, (void*)i);//多次点击
}
//文件系统
if(!LittleFS.begin(true)){
logs("LittleFS Mount Failed", true);
}
//加载上一次保存的配置
loadConfig();
loadClick(currentBTN);
}
void loop(){
delay(10);
for (int i=0; i<BTNSNUM; i++){
OBTNS[i].tick();
}
}