Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <ESP8266WiFi.h>
- #include <IRremoteESP8266.h>
- #include <IRsend.h>
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Global definitions (should be moved to a header file)
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- const int STATUS_PIN = 13;
- #define M_BIT_DURATION_IN_USEC (976-25) //Duration of a logical "1"
- #define S_BIT_DURATION_IN_USEC (976+30) //Duration of a logical "0"
- #define M_TOTAL_DURATION_CORRECTION (103) //Correction factor due to inaccuracies in generation
- #define S_TOTAL_DURATION_CORRECTION (-130) //Correction factor due to inaccuracies in generation
- #define BASE_TEMPERATURE (15)
- #define DATA_STREAM_SIZE (3+3+32*2+2*2)
- #define DURATION_ARRAY_SIZE (DATA_STREAM_SIZE*2+1)
- #define INPUT_ARRAY_SIZE (4)
- #define RAWBUF 100 // Length of raw duration buffer
- typedef enum {
- FAN_LOW = 0,
- FAN_MED,
- FAN_HIGH,
- FAN_AUTO,
- } fanSpeed_e;
- typedef enum {
- MODE_COOL = 1,
- MODE_HEAT,
- MODE_AUTO,
- MODE_DRY,
- MODE_FAN
- } mode_e;
- typedef enum {
- TX_OFF = 0,
- TX_ON
- } txMode_e;
- #pragma pack(push)
- #pragma pack(1)
- /////////////////////////////////////////////////////////
- // AC Status Control Word
- /////////////////////////////////////////////////////////
- typedef union{
- struct{
- uint32_t offMinutes :3; //Off timer control: tens of minutes to wait. Range: 0-5
- uint32_t offHours :5; //Off timer control: hours to wait. Range: 0-23
- uint32_t onMinutes :3; //On time control: tens of minutes to wait. Range: 0-5
- uint32_t onHours :5; //On time control: hours to wait. Range: 0-23
- uint32_t sleep :1; //Sleep mode. On(1)/off(0)
- uint32_t temprature :4; //Temperature. Range: 0(min)-15(max)
- uint32_t reserved1 :2; //Unused?
- uint32_t tilt :1; //Tilt control. On(1)/off(0)
- uint32_t tilt2 :1; //Tile2/Unused?
- uint32_t reserved0 :1; //Unused?
- uint32_t fanSpeed :2; //Fan speed. Min(0)/Med(1)/MAX(2)/AUTO(3)
- uint32_t mode :3; //Mode select. COOL(1)/HEAT(2)/AUTO(3)/DRY(4)/FAN(5)
- uint32_t power :1; //Toggle On/off. Toggle(1)/No change(0)
- };
- uint32_t rawVal;
- } acStatus_t;
- /////////////////////////////////////////////////////////
- // General program control
- /////////////////////////////////////////////////////////
- typedef struct{
- uint8_t tx; //Enable(1)/disable(0) IR transmission
- } progStatus_t;
- #pragma pack(pop)
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Global variables
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- IRsend irsend(4);
- acStatus_t acStatus={0,0,0,0,0,(28-BASE_TEMPERATURE),0,0,0,0,FAN_LOW, MODE_HEAT,0}; //Initialize default status
- progStatus_t progStatus={TX_ON};
- volatile boolean stringComplete = false; //Global flag for CMD parsing
- byte inputArray[INPUT_ARRAY_SIZE+1]={0}; //Buffer for CMD storage. Sets a trailing "0" to end strings
- uint8_t dataStream[DATA_STREAM_SIZE]={}; //Buffer for manchester code generation
- unsigned int rawCodes[DURATION_ARRAY_SIZE]; //Buffer for raw mark/space durations to be sent
- uint16_t rawCodes16[DURATION_ARRAY_SIZE];
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Send the IR code
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void sendCode(uint32_t codeLen) {
- // Assume 38 KHz
- for (int i = 0; i < DURATION_ARRAY_SIZE; ++i)
- {
- rawCodes16[i] = rawCodes[i];
- }
- irsend.sendRaw(rawCodes16, codeLen, 38);
- }
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Converts the AC Status DWORD to a '01/10' Manchester Code stream, adding the required prefix and suffix
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- uint8_t statusToDataStream(uint8_t* dataStream, acStatus_t& acStatus){
- uint8_t bitBuffer[32];
- uint32_t value=acStatus.rawVal;
- for (uint8_t i=0;i<32;i++){
- uint32_t bitVal=((value&0x80000000)==0)?0:1;
- bitBuffer[i]=bitVal;
- value=(value<<1);
- }
- //Write prefix
- uint8_t idx=0;
- dataStream[idx++]=1;
- dataStream[idx++]=1;
- dataStream[idx++]=1;
- dataStream[idx++]=0;
- dataStream[idx++]=0;
- dataStream[idx++]=0;
- //Write actaul status
- for(uint8_t i=0;i<32;i++){
- uint8_t bitVal=bitBuffer[i];
- dataStream[idx++] = (bitVal==0)?1:0;
- dataStream[idx++] = (bitVal==0)?0:1;
- }
- //Write Suffix
- dataStream[idx++]=0;
- dataStream[idx++]=1;
- dataStream[idx++]=1;
- dataStream[idx++]=0;
- return(idx);
- }
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Converts the the '01/10' Manchester Code data stream to a "Raw Durations Buffer", as required by IRSend
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- uint8_t dataStreamToDurations(uint8_t* srcData, uint8_t len){
- //Assuming data stream begins with HIGH
- uint8_t smIdx=0;
- uint32_t duration=M_BIT_DURATION_IN_USEC;
- for (uint8_t streamIdx=1;streamIdx<len;streamIdx++){
- if (smIdx==RAWBUF){
- break;
- }
- if (srcData[streamIdx]==srcData[streamIdx-1]){ //No change, accumulate duration
- if (srcData[streamIdx]==1){
- duration+=M_BIT_DURATION_IN_USEC;
- }else{
- duration+=S_BIT_DURATION_IN_USEC;
- }
- }else{
- if (srcData[streamIdx]==1){ //Level changed, save total duration
- rawCodes[smIdx]=duration+M_TOTAL_DURATION_CORRECTION;
- duration=M_BIT_DURATION_IN_USEC;
- }else{
- rawCodes[smIdx]=duration+S_TOTAL_DURATION_CORRECTION;;
- duration=S_BIT_DURATION_IN_USEC;
- }
- smIdx++;
- }
- if(smIdx>=DURATION_ARRAY_SIZE){
- Serial.print("Cannot create MARK/SPACE duration array"); //This should not happen
- return(smIdx);
- }
- }
- rawCodes[smIdx]=duration; //Save last duration
- return(smIdx+1);
- }
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Dump a raw duration buffer to the serial port (for debug)
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void printCode(unsigned int * durationBuff, uint8_t len){
- for (int i = 0; i < len; i++) {
- if ((i % 2)==0) {
- // Mark
- Serial.print(" m");
- }else {
- // Space
- Serial.print(" s");
- }
- Serial.print(durationBuff[i], DEC);
- }
- Serial.println("");
- return;
- }
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Dump the AC Status to the serial port
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void printStatus(){
- Serial.print("[P:");
- Serial.print(acStatus.power);
- Serial.print(" M:");
- Serial.print(acStatus.mode);
- Serial.print(" F:");
- Serial.print(acStatus.fanSpeed);
- Serial.print(" L:");
- Serial.print(acStatus.tilt2);
- Serial.print(" I:");
- Serial.print(acStatus.tilt);
- Serial.print(" T:");
- Serial.print(acStatus.temprature);
- Serial.print(" S:");
- Serial.print(acStatus.sleep);
- Serial.print(" oN:");
- Serial.print(acStatus.onHours);
- Serial.print(":");
- Serial.print(acStatus.onMinutes);
- Serial.print(" Off:");
- Serial.print(acStatus.offHours);
- Serial.print(":");
- Serial.print(acStatus.offMinutes);
- Serial.print("][0x");
- Serial.print(acStatus.rawVal,HEX);
- Serial.print("][tX:");
- Serial.print(progStatus.tx);
- Serial.println("]");
- }
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Setup the serial communication, pin modes, etc.
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void setup()
- {
- Serial.begin(9600);
- pinMode(STATUS_PIN, OUTPUT);
- Serial.println("Runnning ac_rc");
- printStatus();
- irsend.begin();
- }
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Main loop: Wait for CMD from serial port, then send IR code
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void loop() {
- serialEvent();
- /////////////////////////////////////////////////////////
- // Step 0: Parse CMD from serial port
- /////////////////////////////////////////////////////////
- if(stringComplete!=false){ //Wait for control word from serial port
- stringComplete = false;
- uint8_t cmd=inputArray[0]; //Get control character
- uint8_t cmdVal=atoi((const char*)&inputArray[1]); //Get command value
- Serial.print("CMD:");
- Serial.println((char*)inputArray);
- acStatus.power=0; //The "Power" property is momentary, needs to be reset to avoid unintended on/off toggle
- switch(cmd){
- case 'P':
- acStatus.power=1;
- break;
- case 'M':
- acStatus.mode=cmdVal;
- break;
- case 'F':
- acStatus.fanSpeed=cmdVal;
- break;
- case 'L':
- acStatus.tilt2=cmdVal;
- break;
- case 'I':
- acStatus.tilt=cmdVal;
- break;
- case 'T':
- acStatus.temprature=cmdVal;
- break;
- case 'S':
- acStatus.sleep=cmdVal;
- break;
- case 'N':
- acStatus.onHours=cmdVal/6;
- acStatus.onMinutes=cmdVal%6;
- break;
- case 'O':
- acStatus.offHours=cmdVal/6;
- acStatus.offMinutes=cmdVal%6;
- break;
- case 'X':
- progStatus.tx=cmdVal;
- printStatus();
- return; //Don't continue
- break;
- case 'U':
- printStatus();
- return; //Don't continue
- break;
- default:
- Serial.println("Error decoding CMD!");
- return; //Don't continue past here...
- }
- printStatus();
- /////////////////////////////////////////////////////////
- // Step 1: Create data stream from status
- /////////////////////////////////////////////////////////
- uint8_t dataLen=statusToDataStream(dataStream,acStatus); //Create a data stream from the status
- if (dataLen!=DATA_STREAM_SIZE){
- Serial.print("Error! Unexpected code length (");
- Serial.print(dataLen);
- Serial.println(")");
- return;
- }
- //At this point, dataLen=74
- /////////////////////////////////////////////////////////
- // Step 2: Convert data stream to durations array
- /////////////////////////////////////////////////////////
- uint8_t len=dataStreamToDurations(dataStream,dataLen);
- //printCode(rawCodes,len); //Dump duration array to serial port
- /////////////////////////////////////////////////////////
- // Step 3: Send the IR code.
- // Data is transmitted six times:
- // {data,data,data,BREAK,data,data,data}
- /////////////////////////////////////////////////////////
- if (progStatus.tx!=0){
- Serial.print("Sending code...");
- digitalWrite(STATUS_PIN, HIGH);
- //Send data 3 times
- for (uint8_t i=0;i<3;i++){ //Data needs to be send 3 times
- sendCode(len);
- }
- //Send BREAK
- irsend.mark(4*M_BIT_DURATION_IN_USEC+M_TOTAL_DURATION_CORRECTION);
- irsend.space(33370);
- //Send data 3 times more
- for (uint8_t i=0;i<3;i++){
- sendCode(len);
- }
- digitalWrite(STATUS_PIN, LOW);
- Serial.println("Done!");
- }
- Serial.println("");
- }//stringComplete
- }
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Process incoming serial communication.
- // Flag "complete" when end of string isdetected.
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void serialEvent(){
- static byte inputPos=0;
- while (Serial.available()) {
- // get the new byte:
- char inChar = (char)Serial.read();
- inputArray[inputPos]=inChar;
- inputPos=(inputPos+1)%INPUT_ARRAY_SIZE;
- // if the incoming character is a newline or a carriage return, set a flag
- // so the main loop can do something about it:
- if (inChar == '\n' || inChar == '\r' ||inChar == 0) {
- inputPos=0;
- stringComplete=1;
- }else{
- stringComplete=0;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement