Skip to content

Commit

Permalink
Merge pull request #75 from OpenSprinkler/dev-218.2
Browse files Browse the repository at this point in the history
Dev 218.2
  • Loading branch information
rayshobby committed Aug 19, 2018
2 parents a15e5e1 + e87166a commit 6cfddc9
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 45 deletions.
203 changes: 164 additions & 39 deletions OpenSprinkler.cpp
Expand Up @@ -63,6 +63,7 @@ const char ifkey_filename[] PROGMEM = IFTTT_KEY_FILENAME;
#ifdef ESP8266
const char wifi_filename[] PROGMEM = WIFI_FILENAME;
byte OpenSprinkler::state = OS_STATE_INITIAL;
byte OpenSprinkler::prev_station_bits[MAX_EXT_BOARDS+1];
WiFiConfig OpenSprinkler::wifi_config = {WIFI_MODE_AP, "", ""};
IOEXP* OpenSprinkler::expanders[(MAX_EXT_BOARDS+1)/2];
IOEXP* OpenSprinkler::mainio;
Expand Down Expand Up @@ -205,7 +206,7 @@ const char op_prompts[] PROGMEM =
"Factory reset? ";

/** Option maximum values (stored in progmem) */
const char op_max[] PROGMEM = {
const byte op_max[] PROGMEM = {
0,
108,
1,
Expand Down Expand Up @@ -845,48 +846,153 @@ void OpenSprinkler::begin() {
#endif
}

/** Apply all station bits
* !!! This will activate/deactivate valves !!!
*/
void OpenSprinkler::apply_all_station_bits() {

#ifdef ESP8266
// Handle DC booster
if((hw_type==HW_TYPE_DC) && engage_booster) {
// for DC controller: boost voltage
digitalWriteExt(PIN_BOOST_EN, LOW); // disable output path
digitalWriteExt(PIN_BOOST, HIGH); // enable boost converter
delay((int)options[OPTION_BOOST_TIME]<<2); // wait for booster to charge
digitalWriteExt(PIN_BOOST, LOW); // disable boost converter
digitalWriteExt(PIN_BOOST_EN, HIGH); // enable output path
engage_booster = 0;
}
/** LATCH boost voltage
*
*/
void OpenSprinkler::latch_boost() {
digitalWriteExt(PIN_BOOST, HIGH); // enable boost converter
delay((int)options[OPTION_BOOST_TIME]<<2); // wait for booster to charge
digitalWriteExt(PIN_BOOST, LOW); // disable boost converter
}

if(drio->type==IOEXP_TYPE_8574) {
/* revision 0 uses PCF8574 with active low logic, so all bits must be flipped */
drio->i2c_write(NXP_OUTPUT_REG, ~station_bits[0]);
} else if(drio->type==IOEXP_TYPE_9555) {
/* revision 1 uses PCA9555 with active high logic */
/** Set all zones (for LATCH controller)
* This function sets all zone pins (including COM) to a specified value
*/
void OpenSprinkler::latch_setallzonepins(byte value) {
digitalWriteExt(PIN_LATCH_COM, value); // set latch com pin
// Handle driver board (on main controller)
if(drio->type==IOEXP_TYPE_9555) { // LATCH contorller only uses PCA9555, no other type
uint16_t reg = drio->i2c_read(NXP_OUTPUT_REG); // read current output reg value
reg = (reg&0xFF00) | station_bits[0]; // output channels are the low 8-bit
if(value) reg |= 0x00FF; // first 8 zones are the lowest 8 bits of main driver board
else reg &= 0xFF00;
drio->i2c_write(NXP_OUTPUT_REG, reg); // write value to register
}

for(int i=0;i<MAX_EXT_BOARDS/2;i++) {
uint16_t data = station_bits[i*2+2];
data = (data<<8) + station_bits[i*2+1];
// Handle all expansion boards
for(byte i=0;i<MAX_EXT_BOARDS/2;i++) { //
if(expanders[i]->type==IOEXP_TYPE_9555) {
expanders[i]->i2c_write(NXP_OUTPUT_REG, data);
} else {
expanders[i]->i2c_write(NXP_OUTPUT_REG, ~data);
//pcf_write16(EXP_I2CADDR_BASE+i, ~data);
expanders[i]->i2c_write(NXP_OUTPUT_REG, value?0xFFFF:0x0000);
}
}
}

/*if((hw_type==HW_TYPE_DC) && engage_booster) {
// for DC controller: enable output path
}*/

/** Set one zone (for LATCH controller)
* This function sets one specified zone pin to a specified value
*/
void OpenSprinkler::latch_setzonepin(byte sid, byte value) {
if(sid<8) { // on main controller
if(drio->type==IOEXP_TYPE_9555) { // LATCH contorller only uses PCA9555, no other type
uint16_t reg = drio->i2c_read(NXP_OUTPUT_REG); // read current output reg value
if(value) reg |= (1<<sid);
else reg &= (~(1<<sid));
drio->i2c_write(NXP_OUTPUT_REG, reg); // write value to register
}
} else { // on expander
byte bid=(sid-8)>>4;
uint16_t s=(sid-8)&0x0F;
if(expanders[bid]->type==IOEXP_TYPE_9555) {
uint16_t reg = expanders[bid]->i2c_read(NXP_OUTPUT_REG); // read current output reg value
if(value) reg |= (1<<s);
else reg &= (~(1<<s));
expanders[bid]->i2c_write(NXP_OUTPUT_REG, reg);
}
}
}

/** LATCH open / close a station
*
*/
void OpenSprinkler::latch_open(byte sid) {
latch_boost(); // boost voltage
latch_setallzonepins(HIGH); // set all switches to HIGH, including COM
latch_setzonepin(sid, LOW); // set the specified switch to LOW
delay(1); // delay 1 ms for all gates to stablize
digitalWriteExt(PIN_BOOST_EN, HIGH); // dump boosted voltage
delay(100); // for 100ms
latch_setzonepin(sid, HIGH); // set the specified switch back to HIGH
digitalWriteExt(PIN_BOOST_EN, LOW); // disable boosted voltage
}

void OpenSprinkler::latch_close(byte sid) {
latch_boost(); // boost voltage
latch_setallzonepins(LOW); // set all switches to LOW, including COM
latch_setzonepin(sid, HIGH);// set the specified switch to HIGH
delay(1); // delay 1 ms for all gates to stablize
digitalWriteExt(PIN_BOOST_EN, HIGH); // dump boosted voltage
delay(100); // for 100ms
latch_setzonepin(sid, LOW); // set the specified switch back to LOW
digitalWriteExt(PIN_BOOST_EN, LOW); // disable boosted voltage
latch_setallzonepins(HIGH); // set all switches back to HIGH
}

/**
* LATCH version of apply_all_station_bits
*/
void OpenSprinkler::latch_apply_all_station_bits() {
if(hw_type==HW_TYPE_LATCH && engage_booster) {
for(byte i=0;i<nstations;i++) {
byte bid=i>>3;
byte s=i&0x07;
byte mask=(byte)1<<s;
if(station_bits[bid] & mask) {
if(prev_station_bits[bid] & mask) continue; // already set
latch_open(i);
} else {
if(!(prev_station_bits[bid] & mask)) continue; // already reset
latch_close(i);
}
}
engage_booster = 0;
memcpy(prev_station_bits, station_bits, MAX_EXT_BOARDS+1);
}
}
#endif

/** Apply all station bits
* !!! This will activate/deactivate valves !!!
*/
void OpenSprinkler::apply_all_station_bits() {

#ifdef ESP8266
if(hw_type==HW_TYPE_LATCH) {
// if controller type is latching, the control mechanism is different
// hence will be handled separately
latch_apply_all_station_bits();
} else {
// Handle DC booster
if(hw_type==HW_TYPE_DC && engage_booster) {
// for DC controller: boost voltage and enable output path
digitalWriteExt(PIN_BOOST_EN, LOW); // disfable output path
digitalWriteExt(PIN_BOOST, HIGH); // enable boost converter
delay((int)options[OPTION_BOOST_TIME]<<2); // wait for booster to charge
digitalWriteExt(PIN_BOOST, LOW); // disable boost converter
digitalWriteExt(PIN_BOOST_EN, HIGH); // enable output path
engage_booster = 0;
}

// Handle driver board (on main controller)
if(drio->type==IOEXP_TYPE_8574) {
/* revision 0 uses PCF8574 with active low logic, so all bits must be flipped */
drio->i2c_write(NXP_OUTPUT_REG, ~station_bits[0]);
} else if(drio->type==IOEXP_TYPE_9555) {
/* revision 1 uses PCA9555 with active high logic */
uint16_t reg = drio->i2c_read(NXP_OUTPUT_REG); // read current output reg value
reg = (reg&0xFF00) | station_bits[0]; // output channels are the low 8-bit
drio->i2c_write(NXP_OUTPUT_REG, reg); // write value to register
}

// Handle expansion boards
for(int i=0;i<MAX_EXT_BOARDS/2;i++) {
uint16_t data = station_bits[i*2+2];
data = (data<<8) + station_bits[i*2+1];
if(expanders[i]->type==IOEXP_TYPE_9555) {
expanders[i]->i2c_write(NXP_OUTPUT_REG, data);
} else {
expanders[i]->i2c_write(NXP_OUTPUT_REG, ~data);
}
}
}

byte bid, s, sbits;
#else
digitalWrite(PIN_SR_LATCH, LOW);
Expand Down Expand Up @@ -933,7 +1039,6 @@ void OpenSprinkler::apply_all_station_bits() {

if(options[OPTION_SPE_AUTO_REFRESH]) {
// handle refresh of RF and remote stations
// each time apply_all_station_bits is called
// we refresh the station whose index is the current time modulo MAX_NUM_STATIONS
static byte last_sid = 0;
byte sid = now() % MAX_NUM_STATIONS;
Expand Down Expand Up @@ -984,12 +1089,14 @@ uint16_t OpenSprinkler::read_current() {
#else
scale = 16.11;
#endif
} else {
} else if (hw_type == HW_TYPE_AC) {
#if defined(ESP8266)
scale = 3.45;
#else
scale = 11.39;
#endif
} else {
scale = 0.0; // for other controllers, current is 0
}
/* do an average */
const byte K = 5;
Expand Down Expand Up @@ -1197,6 +1304,11 @@ byte OpenSprinkler::set_station_bit(byte sid, byte value) {
if(!((*data)&mask)) return 0; // if bit is already reset, return no change
else {
(*data) = (*data) & (~mask);
#if defined(ESP8266)
if(hw_type == HW_TYPE_LATCH) {
engage_booster = true; // if LATCH controller, engage booster when bit changes
}
#endif
switch_special_station(sid, 0); // handle special stations
return 255;
}
Expand Down Expand Up @@ -1680,8 +1792,8 @@ void OpenSprinkler::options_setup() {
if (!button) {
// flash screen
lcd_print_line_clear_pgm(PSTR(" OpenSprinkler"),0);
lcd.setCursor(2, 1);
lcd_print_pgm(PSTR("HW v"));
lcd.setCursor((hw_type==HW_TYPE_LATCH)?2:4, 1);
lcd_print_pgm(PSTR("v"));
byte hwv = options[OPTION_HW_VERSION];
lcd.print((char)('0'+(hwv/10)));
lcd.print('.');
Expand All @@ -1691,12 +1803,25 @@ void OpenSprinkler::options_setup() {
lcd_print_pgm(PSTR(" DC"));
break;
case HW_TYPE_LATCH:
lcd_print_pgm(PSTR(" LA"));
lcd_print_pgm(PSTR(" LATCH"));
break;
default:
lcd_print_pgm(PSTR(" AC"));
}
delay(1500);
#ifdef ESP8266
lcd.setCursor(2, 1);
lcd_print_pgm(PSTR("FW "));
lcd.print((char)('0'+(OS_FW_VERSION/100)));
lcd.print('.');
lcd.print((char)('0'+((OS_FW_VERSION/10)%10)));
lcd.print('.');
lcd.print((char)('0'+(OS_FW_VERSION%10)));
lcd.print('(');
lcd.print(OS_FW_MINOR);
lcd.print(')');
delay(1000);
#endif
}
#endif
}
Expand Down
12 changes: 10 additions & 2 deletions OpenSprinkler.h
Expand Up @@ -115,7 +115,7 @@ struct ConStatus {
extern const char wtopts_filename[];
extern const char stns_filename[];
extern const char ifkey_filename[];
extern const char op_max[];
extern const byte op_max[];
extern const char op_json_names[];
#ifdef ESP8266
struct WiFiConfig {
Expand Down Expand Up @@ -264,7 +264,15 @@ class OpenSprinkler {
#if defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega1284__) || defined(ESP8266)
static byte engage_booster;
#endif

#if defined(ESP8266)
static void latch_boost();
static void latch_open(byte sid);
static void latch_close(byte sid);
static void latch_setzonepin(byte sid, byte value);
static void latch_setallzonepins(byte value);
static void latch_apply_all_station_bits();
static byte prev_station_bits[];
#endif
#endif // LCD functions
};

Expand Down
2 changes: 1 addition & 1 deletion defines.h
Expand Up @@ -38,7 +38,7 @@ typedef unsigned long ulong;
// if this number is different from the one stored in non-volatile memory
// a device reset will be automatically triggered

#define OS_FW_MINOR 1 // Firmware minor version
#define OS_FW_MINOR 2 // Firmware minor version

/** Hardware version base numbers */
#define OS_HW_VERSION_BASE 0x00
Expand Down
16 changes: 16 additions & 0 deletions program.cpp
Expand Up @@ -332,4 +332,20 @@ void ProgramData::drem_to_absolute(byte days[2]) {
days[0] = (byte)(((os.now_tz()/SECS_PER_DAY) + rem_rel) % inv);
}

// set the enable bit
byte ProgramData::set_flagbit(byte pid, byte bid, byte value) {
if (pid >= nprograms) return 0;
if (0) {
// handle SD card
} else {
byte flag;
unsigned int addr = ADDR_PROGRAMDATA + (unsigned int)pid * PROGRAMSTRUCT_SIZE;
flag=nvm_read_byte((const byte *)addr);
if(value) flag|=(1<<bid);
else flag&=(~(1<<bid));
nvm_write_byte((const byte *)addr, flag);
}
return 1;
}


3 changes: 3 additions & 0 deletions program.h
Expand Up @@ -59,6 +59,8 @@ struct LogStruct {
#define STARTTIME_SUNSET_BIT 13
#define STARTTIME_SIGN_BIT 12

#define PROGRAMSTRUCT_EN_BIT 0
#define PROGRAMSTRUCT_UWT_BIT 1
/** Program data structure */
class ProgramStruct {
public:
Expand Down Expand Up @@ -155,6 +157,7 @@ class ProgramData {
static void read(byte pid, ProgramStruct *buf);
static byte add(ProgramStruct *buf);
static byte modify(byte pid, ProgramStruct *buf);
static byte set_flagbit(byte pid, byte bid, byte value);
static void moveup(byte pid);
static byte del(byte pid);
static void drem_to_relative(byte days[2]); // absolute to relative reminder conversion
Expand Down
21 changes: 18 additions & 3 deletions server.cpp
Expand Up @@ -940,6 +940,20 @@ void server_change_program() {
int pid=atoi(tmp_buffer);
if (!(pid>=-1 && pid< pd.nprograms)) handle_return(HTML_DATA_OUTOFBOUND);

// check if "en" parameter is present
if (findKeyVal(p, tmp_buffer, TMP_BUFFER_SIZE, PSTR("en"), true)) {
if(pid<0) handle_return(HTML_DATA_OUTOFBOUND);
pd.set_flagbit(pid, PROGRAMSTRUCT_EN_BIT, (tmp_buffer[0]=='0')?0:1);
handle_return(HTML_SUCCESS);
}

// check if "uwt" parameter is present
if (findKeyVal(p, tmp_buffer, TMP_BUFFER_SIZE, PSTR("uwt"), true)) {
if(pid<0) handle_return(HTML_DATA_OUTOFBOUND);
pd.set_flagbit(pid, PROGRAMSTRUCT_UWT_BIT, (tmp_buffer[0]=='0')?0:1);
handle_return(HTML_SUCCESS);
}

// parse program name
if (findKeyVal(p, tmp_buffer, TMP_BUFFER_SIZE, PSTR("name"), true)) {
urlDecode(tmp_buffer);
Expand Down Expand Up @@ -1519,6 +1533,10 @@ void server_change_options()
* cpw: confirm new password
*/
void server_change_password() {
#if defined(DEMO)
handle_return(HTML_SUCCESS); // do not allow chnaging password for demo
#endif

#ifdef ESP8266
char* p = NULL;
if(!process_password()) return;
Expand All @@ -1528,9 +1546,6 @@ void server_change_password() {
if (findKeyVal(p, tmp_buffer, TMP_BUFFER_SIZE, PSTR("npw"), true)) {
char tbuf2[TMP_BUFFER_SIZE];
if (findKeyVal(p, tbuf2, TMP_BUFFER_SIZE, PSTR("cpw"), true) && strncmp(tmp_buffer, tbuf2, MAX_USER_PASSWORD) == 0) {
#if defined(DEMO)
handle_return(HTML_SUCCESS);
#endif
urlDecode(tmp_buffer);
tmp_buffer[MAX_USER_PASSWORD-1]=0; // make sure we don't exceed the maximum size
nvm_write_block(tmp_buffer, (void*)ADDR_NVM_PASSWORD, strlen(tmp_buffer)+1);
Expand Down

0 comments on commit 6cfddc9

Please sign in to comment.