Skip to content

Releases: tahunus/AutoInflate

0.3.3V

29 Dec 19:15
cf2c3f7
Compare
Choose a tag to compare

An API to interact with AUTOINFLATE via a Wi-Fi connection using UDP packets.

Content

What it is
How to add it to AUTOINFLATE
How it works


What it is

An API using UDP messages (see What is UDP) formatted in JSON (using the v6 of ArduinoJson library) and managed by Espressif's Async UDP to interact with AUTOINFLATE via an outside microprocessor, single board computer, smartphone or PC/Mac.

The API includes methods to retrieve the operating variables as currently defined & saved in AUTOINFLATE, to set & save new values for these variables and, to run defined inflation cycles.

To avoid possible operating conflicts, UDP requests received in the unit during inflation cycles or while the unit's menu is in CONFIG mode will return an error response. The whole API is encapsulated in a Class to avoid present and future conflicts with variable or function names with the rest of AUTOINFLATE's code.


How to add it to AUTOINFLATE

Step 1. In the main .ino program, add 3 lines of code:

  • #include "WiFi_API.h" as the last include statement
  • wifiAPI.begin(); as the last statement in setup()
  • wifiAPI.chkProcess(); as the last statement in loop()

Step 2. add these 2 files to the folder where the main .ino file resides

  • WiFi_API.h
  • WiFi_API_config.h

Step 3. enter the required credentials in WiFI_API_config.h

const char* ssid = "yourNetworkID";
const char* password = "yourPassword";
const int UDPport = 12345;  // define a 4 or 5 digit port 

#define DEBUG_PRINT  //if commented out, all debug serial output statments become empty when compiled

#define STATIC_IP  //if commented out, IP & DNS will come from router's DHCP
#ifdef STATIC_IP
  IPAddress staticIP(192, 168, 1, 69); //if this IP is reserved in your router, connection can be faster
  IPAddress gateway(192, 168, 1, 1);
  IPAddress subnet(255, 255, 255, 0);
  IPAddress primaryDNS(8, 8, 8, 8);
  IPAddress secondaryDNS(192, 168, 1, 1);
#endif

Step 4. Compile & load.


How it works

Definition of API Messages

note: Methods, Groups and Parameter names are case sensitive and in JSON format

Methods

  • run : execute an defined inflation cycle
  • getConfig : retrieve the parameters stored in the device for a particular group
  • setConfig : send and save parameters for a particular group

Groups

  • profileRUN : inflation cycle using the profile option for multiple cycles based on total time
  • hugRUN : one time inflation cycle
  • airSYS : inflation operating limits
  • config : pump operation limits
  • globals : selected global variables

Parameters

group parameter min max units
profileRUN highPressure 0 MaxPressure PSI x 10
onTime 0 599 seconds
offTime 0 599 seconds
cycletime 0 5999 seconds
hugRUN hugTime 0 599 seconds
hugPressure 0 MaxPressure seconds
airSYS maxPumpPWM 0 51 ?
maxPressure 0 MaxPressure PSI x 10
thresholdPressure 0 5 ?
config minPumpPWM 200 1023 ?
freq 2 199 ?
clearALL 0 1 boolean
globals MaxPressure 0 50 PSI x 10
battery Volts. Read-only

Sample requests & responses

Request
{
  "method" : "getConfig",
  "group" : "hugRUN"
}
Response
{
  "method" : "getConfig",
  "group" : "hugRUN",
  "hugTime" : 30,
  "hugPressure" : 30
}

Request
{
  "method" : "setConfig",
  "group" : "hugRUN",
  "hugTime" : 30,
  "hugPressure" : 30
}
Response
{
  "method" : "getConfig",
  "group" : "hugRUN",
  "response" : "Success"
}

To test sending and receiving UDP messages prior to developing some program, you can use a simple packet sender. For windows I'm using Network Tools Collection Desktop Edition

Full Changelog: 0.3.2V...0.3.3V

..

0.3.2V

25 Dec 13:53
288fec6
Compare
Choose a tag to compare

Keeps the exact same functionality as 0.3.1V but collects functions into 5 logical groups:

  1. AUTOINFLATE_0.3.2V.ino - main program with #include´s, setup() and loop()
  2. globalVariables.h - self explained
  3. graphics.h - variables with bitmaps for display images
  4. hwControl.h - hardware control (i.e. timers, interrupts, etc)
  5. frontEnd.h - user interface (i.e. menus, etc)
  6. backEnd.h - operations and control (i.e. operate pump, run inflation profiles, store data, etc.)

For better reference, see matrix below. Rows have the functions called by the function in that row. Columns have the functions that call the function in that column.

image

Some functions were refactored:

runningAnimation()

Was defined in line 1505 and called in line 545 inside mainPage(). Since it was used only in mainPage(), the code was refactored first declaring a pointer array to the 3 image files defined in frontEnd.h, line 11 as

static const unsigned char* image_VEST2_ANIMATIONS[] U8X8_PROGMEM = { //pointer array to the graphics variables
    image_VEST2_ANIMATION_1_bits,
    image_VEST2_ANIMATION_2_bits,
    image_VEST2_ANIMATION_3_bits
    //more animations...
};

and the code inserted directly into mainPage() (now in line 76 of frontEnd.h)

  if(airSys.pumpState) {
    u8g2.drawXBMP(8, 29, 25, 31, image_VEST2_ANIMATIONS[frameCount]); //frameCount always >= 0 && <= 2
    if(currentMillis - animationPreviousMillis >= animationFlipInterval) {
      animationPreviousMillis = currentMillis;
      frameCount++;
      if (frameCount > 2) frameCount = 0;
    }
  }

configMainPage()

Was defined in line 603 using 172 lines of code. It was refactored using only 19 lines of code (now defined in line 101 of frontEnd.h) by first declaring a struct with the screen coordinates of all images and text:

struct ConfigMainPage {
    const char* text;
    int txtX;
    const uint8_t* image; //using a pointer to avoid making a copy of a large variable
    int imgX, imgY, imgW, imgH;
};
ConfigMainPage configMainMenu[] = { //values for encoderInput 0..8
    {"BACK",      39, image_Pin_arrow_left_9x7_bits,  0, 57,  9,  7},  //used in all subConfig pages
    {"PROFILE",   39, image_profile_bits,             6,  9, 28, 29},
    {"HUG",       63, image_HUG_LARGE_bits,          24, 12, 32, 29},
    {"AIRSYS",    49, image_PUMP1_bits,               7,  9, 36, 28},
    {"MOTION",    49, image_TAP_bits,                 6,  4, 38, 36},
    {"CONFIG",    51, image_GEAR_bits,                6,  3, 41, 41},
    {"WIFI",      66, image_WIRELESS_bits,           10,  9, 48, 34},    
    {"-----TBD1", 11, nullptr,                        0,  0,  0,  0},
    {"-----TBD2", 11, nullptr,                        0,  0,  0,  0}  
    //more configurations...
};
int frameX = 17; //X position for first frame. Subsequent frames spaced @ frameW +2 to leave 1 pixel between frames
int frameY = 54;
int frameW = 10;
int frameH = 10;

and using encoderInput as the index to retrieve data from the array:

void configMainPage() {
  //draw the "BACK" arrow and the frames for all 8 config menu options
  u8g2.setDrawColor(1);
  u8g2.drawXBMP(0, 57, 9, 7, image_Pin_arrow_left_9x7_bits);
  for (int i = 0; i < 8; i++) 
    u8g2.drawFrame(frameX + (frameW +2) * i, frameY, frameW, frameH);

  //draw the text & image of the option selected by encoderInput
  const ConfigMainPage& cfg = configMainMenu[encoderInput];  //defined as reference (&) to avoid copying a big variable
  u8g2.setFont(u8g2_font_profont22_tr);
  u8g2.drawStr(cfg.txtX, 32, cfg.text);
  u8g2.drawXBMP(cfg.imgX, cfg.imgY, cfg.imgW, cfg.imgH, cfg.image);

  //flash the corresponding frame or the BACK arrow
  u8g2.setDrawColor(!flash);
  if (encoderInput > 0) 
    u8g2.drawBox(frameX + (frameW +2) * (encoderInput -1) +1, frameY +1, frameW -2 , frameH -2);
  else 
    u8g2.drawXBMP(cfg.imgX, cfg.imgY, cfg.imgW, cfg.imgH, cfg.image);
}

configPage1(), configPage2() & configPage3()

They were defined starting in line 777 and now reside in frontEnd.h starting in line 122. The three functions received new local variables defining the screen coordinates for their text strings. For example, in configPage1():

  //define X, Y & W for input field of PRESSURE, ON-TIME, OFF-TIME & CYCLE TIME
  const int txtX[4] = {9,35,57,94}; 
  const int txtY[4] = {21,10,56,23};
  const int txtW[4] = {18,24,24,30};

and using encoderInput as index to retrieve data from the array, plus some other tactics to reduce repetitive code. For example, see this selection using a switch statement in configPage1() (vs nested IF/ELSE statements):

    switch (encoderInput) {
      case 0: u8g2.setDrawColor(!flash);                                  //flash BACK arrow
              u8g2.drawXBMP( 0, 57, 9, 7, image_Pin_arrow_left_9x7_bits);  
              break;
      case 1: encoderInputTemp = (profileVar.highPressure * 0.0146) / 10; //PROFILE PRESSURE
              break;
      case 2: encoderInputTemp = profileVar.onTime;                       //PROFILE ON-TIME
              break;
      case 3: encoderInputTemp = profileVar.offTime;                      //PROFILE OFF-TIME
              break;
      case 4: encoderInputTemp = profileVar.cycleTime;                    //PROFILE CYCLE TIME
              break;
      case 5: SAVE = true; 
              if (!flash) u8g2.drawRBox(104, 53, 24, 11, 1);              //flash SAVE icon
              break;
      case 6: if (!flash) u8g2.drawRBox(90, 52, 12, 12, 3);               //flash HELP icon
    }
    if (encoderInput > 0 && encoderInput < 5 && !flash) //flash the frame around the selected text input
        u8g2.drawFrame(txtX[encoderInput-1] -2, txtY[encoderInput-1] -10, txtW[encoderInput-1], 12);

Total lines of code for the three functions were reduced from 407 to 242.

buttonPressFunc(), encoderInteraction()

buttonPressFunc() was defined in line 1374 and because it was only used by encoderInteraction() (defined in line 1283), it was eliminated and its code refactored and included in the new encoderInteraction() now defined in line 336 of backEnd.h with a reformatted switch statement that also saved 20 lines of code:

void encoderInteraction()  { //ONE TIME EXECUTE
  switch (pageNumber) {
    case 1:
      mainPageActions(); //MAIN PAGE   
      break;
    case 2:
      mainConfigPageActions(); //CONFIG PAGE
      break;
    case 3:   //PROFILE
    case 4:   //HUG
    case 5:   //AIRSYS
    case 6:   //MOTION
    case 7:   //CONFIG
    case 8:   //WIFI
    case 9:   //-----TBD1
    case 10:  //-----TBD2 (and cases 3 thru 9, above)
      configPageActions(); 
      break;
  }
  encoderConstrainValMin = 0;
  encoderConstrainValMax = PageElements[pageNumber];
}

0.3.1V

25 Dec 13:40
fdf4c9f
Compare
Choose a tag to compare

Original files from forked repo