macro ModeFrom2Inputs(manIn, autoInActiveLow, &mode) { if (in(manIn)) { mode = MAN; } else { if (!in(autoInActiveLow)) { mode = AUTO; } else { mode = OFF; } } } macro PumpChannel(id, mode, thermOk, p, onTh, offTh, outNo, &state) { if (thermOk) { if (mode == MAN) { out(outNo) = 1; state = S_RUN; } else { if (mode == AUTO) { if (p < onTh) { out(outNo) = 1; state = S_RUN; } else { if (p > offTh) { out(outNo) = 0; state = S_STOP; } } } else { out(outNo) = 0; state = S_OFF; } } } else { state = S_FAULT; } } macro DryRunFault(id, w, dryLevel, pump, delayMs, clearEdgeIn, &dryFlag) { if (ton("ton1", w < dryLevel && pump, delayMs)) { dryFlag = 1; out(1) = 0; out(2) = 0; out(3) = 0; publish("alarm", "DRY_RUN"); } if (p_edge(in(clearEdgeIn)) && w >= dryLevel) { dryFlag = 0; t_reset("ton1"); } } macro BatteryLowWarn(id, b, blow, bclr, delayMs, &bloFlag) { if (ton("ton1", b < blow, delayMs)) { if (bloFlag == 0) { bloFlag = 1; publish("warning", "BATT_LOW"); } } if (b >= bclr) { bloFlag = 0; t_reset("ton1"); } } macro MqttSetSave(topic, &var) { onmqtt(topic) { if (msg_is_number) { var = msg_value; save(var); } } // NVS writes are limited; avoid frequent SAVE calls. } load(JON, 20); load(JOFF, 40); load(MON, 10); load(MOFF, 30); load(DON, 10); load(DOFF, 30); logn(JON, "-", JOFF, " ", MON, "-", MOFF, " ", DON, "-", DOFF); DRY = 1; BLOW = 11; BCLR = 12; BDELAY = 10000; STATUS = 30000; OFF = 0; AUTO = 1; MAN = 2; S_OFF = 0; S_RUN = 1; S_STOP = 2; S_FAULT = 3; mul = 30; p = 0; b = 0; w = 0; dry = 0; blo = 0; jm = OFF; mm = OFF; dm = OFF; js = S_OFF; ms = S_OFF; ds = S_OFF; error = 0; every(5000) { logn("Pressure: ", p, " mul:", mul); } every(30000) { // simulator switch (mul) { case 30: { mul = 10; break; } case 10: { mul = 6; break; } case 6: { mul = 3; break; } case 3: { mul = 30; break; } default: { mul = 30; break; } } } every(200) { // analogs p = ain(1) / mul + 10; b = ain(2) * 20 / 4; w = ain(3) / mul; tm1ok = !in(7); tm2ok = !in(8); // modes (same pattern, now 1-liners) ModeFrom2Inputs(2, 1, &jm); // jockey: man=in2, auto=active-low in1 ModeFrom2Inputs(4, 3, &mm); // main: man=in4, auto=active-low in3 ModeFrom2Inputs(6, 5, &dm); // diesel: man=in6, auto=active-low in5 pump = out(1) || out(2) || out(3); // faults/warnings DryRunFault("dry", w, DRY, pump, BDELAY, 8, &dry); BatteryLowWarn("batt", b, BLOW, BCLR, BDELAY, &blo); if (dry) { out(1) = 0; out(2) = 0; out(3) = 0; js = S_FAULT; ms = S_FAULT; ds = S_FAULT; } else { PumpChannel("j", jm, tm1ok, p, JON, JOFF, 1, &js); PumpChannel("m", mm, tm2ok, p, MON, MOFF, 2, &ms); PumpChannel("d", dm, 1, p, DON, DOFF, 3, &ds); // diesel has no thermal input in your original logic } if (dry || blo || ms == S_FAULT || js == S_FAULT) { out(4) = 1; error = 1; } else { out(4) = 0; error = 0; } if (ton("status_tick", 1, STATUS)) { t_reset("status_tick"); publish("status", "pressure", p, "battery", b, "water", w, "jockey_mode", jm, "main_mode", mm, "diesel_mode", dm, "jockey_state", js, "main_state", ms, "diesel_state", ds, "jockey_on", JON, "jockey_off", JOFF, "main_on", MON, "main_off", MOFF, "diesel_on", DON, "diesel_off", DOFF, "dry_run_fault", dry, "batt_low", blo, "error", error); } } // MQTT setters (6 lines instead of 6 full macros) MqttSetSave("JON_script", &JON); MqttSetSave("JOFF_script", &JOFF); MqttSetSave("MON_script", &MON); MqttSetSave("MOFF_script", &MOFF); MqttSetSave("DON_script", &DON); MqttSetSave("DOFF_script", &DOFF);