Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
2c35be3
add UI support for target PD voltage; tweak css to make the text-widg…
rayshobby Oct 17, 2025
275d5cf
support for preempt checkbox on manual station run
rayshobby Oct 20, 2025
86d8ba7
fix bug in getSequential function; minor changes to preempt option
rayshobby Oct 20, 2025
1351102
fix bug where deleting a program affects the display status of disabl…
rayshobby Oct 20, 2025
1273c35
fix keyindex mismatch per issue @281
rayshobby Oct 20, 2025
cccdc58
fix log display issue of rain sensor and rain delay events
rayshobby Oct 25, 2025
9d71d4b
remove checking of condition that's always true: isActive always retu…
rayshobby Oct 25, 2025
f094af8
only show scheduling options if there is any existing schedule
rayshobby Oct 25, 2025
763c149
support scheduling options for run-once and run program x from the pr…
rayshobby Oct 26, 2025
bff0994
fix eslint complaint
rayshobby Oct 26, 2025
6385518
fix some condition checking in submitRunonce
rayshobby Oct 26, 2025
077eb53
change pre or preempt terms to qo (queuing option) to be consistent; …
rayshobby Oct 27, 2025
337575c
more qo term consistency checking; add button to clear current alert …
rayshobby Oct 27, 2025
e5b2f7b
set default interval day to 1 (as 0 is not a valid value); this will …
rayshobby Oct 27, 2025
041eeef
add ability to cache selected queue option
rayshobby Oct 27, 2025
a49a717
add firmware guard to features that should be hidden for older firmware
rayshobby Oct 28, 2025
432051d
Merge branch 'master' into support/os34dc
rayshobby Oct 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions www/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -1150,5 +1150,23 @@ button[id^="start_1-"] {
margin-right: 5px;
}

/*
Fix for vertical alignment on desktop/wide screens.
*/
@media screen and (min-width: 480px) {
/* 1. Turn the container into a flexbox */
.ui-field-contain {
display: flex;
align-items: center;
}

/* 2. Remove the old float property that interferes */
.ui-field-contain > label {
float: none !important;
}

/* 3. ADDED: Force the sensor fieldset to take full width */
.ui-field-contain .sensor-options {
width: 100%;
}
}
14 changes: 7 additions & 7 deletions www/js/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,10 @@ window.currLocal = true;
if ( loadedScripts === totalScripts ) {
// Once all scripts loaded, insert main.js
insertScript( assetLocation + "js/main.js", function () {
try {
OSApp.Storage.setItemSync( "testQuota", "true" );
OSApp.Storage.removeItemSync( "testQuota" );
init();
try {
OSApp.Storage.setItemSync( "testQuota", "true" );
OSApp.Storage.removeItemSync( "testQuota" );
init();
} catch ( err ) {
if ( err.code === 22 ) {
document.body.innerHTML = "<div class='spinner'><div class='logo'></div>" +
Expand Down Expand Up @@ -243,8 +243,8 @@ window.currLocal = true;
document.title = "Loading...";

// Inject site information to storage so Application loads current device
OSApp.Storage.setItemSync( "sites", JSON.stringify( sites ) );
OSApp.Storage.setItemSync( "current_site", currentSite );
OSApp.Storage.setItemSync( "sites", JSON.stringify( sites ) );
OSApp.Storage.setItemSync( "current_site", currentSite );
finishInit();
},
wrongPassword = function() {
Expand All @@ -262,7 +262,7 @@ window.currLocal = true;
"<div class='logo'></div><span class='feedback'>Unable to load UI</span>" +
"</div>" );
},
sites = JSON.parse( OSApp.Storage.getItemSync( "sites" ) ),
sites = JSON.parse( OSApp.Storage.getItemSync( "sites" ) ),
loader;

// Fix to allow CORS ajax requests to work on IE8 and 9
Expand Down
4 changes: 2 additions & 2 deletions www/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ OSApp.Constants = {
"wl":23, "den":24, "ipas":25, "devid":26, "con":27, "lit":28, "dim":29, "bst":30, "uwt":31, "ntp1":32, "ntp2":33,
"ntp3":34, "ntp4":35, "lg":36, "mas2":37, "mton2":38, "mtof2":39, "fpr0":41, "fpr1":42, "re":43, "dns1": 44,
"dns2":45, "dns3":46, "dns4":47, "sar":48, "ife":49, "sn1t":50, "sn1o":51, "sn2t":52, "sn2o":53, "sn1on":54,
"sn1of":55, "sn2on":56, "sn2of":57, "subn1":58, "subn2":59, "subn3":60, "subn4":61, "laton":62, "latof":63,
"ife2":64, "imin":65, "imax":66
"sn1of":55, "sn2on":56, "sn2of":57, "subn1":58, "subn2":59, "subn3":60, "subn4":61, "fwire":62, "laton":63, "latof":64,
"ife2":65, "imin":66, "imax":67, "tpdv":68
},
options: { // Option constants
IGNORE_SENSOR_1: 1,
Expand Down
14 changes: 11 additions & 3 deletions www/js/modules/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -970,8 +970,14 @@ OSApp.Dashboard.displayPage = function() {

// Show the remaining time if it's greater than 0
line += " <span id=" + ( qPause ? "'pause" : "'countdown-" ) + sid + "' class='nobr'>(" + OSApp.Dates.sec2hms( rem ) + " " + OSApp.Language._( "remaining" ) + ")</span>";
if ( OSApp.currentSession.controller.status[ sid ] ) {

if ( isRunning ) {
addTimer( sid, rem );
} else {
// Station is scheduled/paused but not running - remove timer if it exists
if ( OSApp.uiState.timers[ "station-" + sid ] ) {
delete OSApp.uiState.timers[ "station-" + sid ];
}
}
}
if ( card.find( ".rem" ).length === 0 ) {
Expand Down Expand Up @@ -1088,8 +1094,10 @@ OSApp.Dashboard.displayPage = function() {
maximum: 64800,
seconds: sites[ currentSite ].lastRunTime[ sid ] > 0 ? sites[ currentSite ].lastRunTime[ sid ] : 0,
helptext: OSApp.Language._( "Enter a duration to manually run " ) + name,
callback: function( duration ) {
OSApp.Firmware.sendToOS( "/cm?sid=" + sid + "&en=1&t=" + duration + "&pw=", "json" ).done( function() {
showQOCheckbox: OSApp.Groups.canPreempt( stationGID ) && OSApp.Stations.isSequential( sid ),
callback: function( duration, qo ) {
var preParam = qo ? "&qo=1" : "";
OSApp.Firmware.sendToOS( "/cm?sid=" + sid + "&en=1&t=" + duration + preParam + "&pw=", "json" ).done( function() {

// Update local state until next device refresh occurs
OSApp.Stations.setPID( sid, OSApp.Constants.options.MANUAL_STATION_PID );
Expand Down
7 changes: 6 additions & 1 deletion www/js/modules/groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,12 @@ OSApp.Groups.numActiveStations = function( gid ) {

// If more than 1 stations (includes the one to be turned off) are active
OSApp.Groups.canShift = function( gid ) {
return OSApp.Groups.numActiveStations( gid ) > 1;
return OSApp.Firmware.checkOSVersion( 220 ) && OSApp.Groups.numActiveStations( gid ) > 1;
};

// If at least 1 station in this group is active
OSApp.Groups.canPreempt = function( gid ) {
return OSApp.Firmware.checkOSVersion( 2214 ) && ( OSApp.Groups.numActiveStations( gid ) > 0 );
};

// Tbh, not sure if this belongs here in groups.js (mellodev)
Expand Down
60 changes: 30 additions & 30 deletions www/js/modules/logs.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ OSApp.Logs.displayPage = function() {
}

$.each( data, function() {
var station = this[ 1 ],
duration = parseInt( this[ 2 ] ),
flowRate = ( typeof this[ 4 ] !== "undefined" ) ? OSApp.Utils.flowRateToVolume( parseFloat( this[ 4 ] ) ) : null;
var station = this[ 1 ],
duration = parseInt( this[ 2 ] ),
flowRate = ( typeof this[ 4 ] !== "undefined" ) ? OSApp.Utils.flowRateToVolume( parseFloat( this[ 4 ] ) ) : null;

// Adjust for negative watering time firmware bug
if ( duration < 0 ) {
Expand Down Expand Up @@ -114,15 +114,15 @@ OSApp.Logs.displayPage = function() {

if ( type === "table" ) {
switch ( grouping ) {
case "station":
var stationItem = [ utc, OSApp.Dates.dhms2str( OSApp.Dates.sec2dhms( duration ) ), station, new Date( utc.getTime() + ( duration * 1000 ) ), flowRate ];
sortedData[ station ].push( stationItem );
break;
case "day":
var day = Math.floor( date.getTime() / 1000 / 60 / 60 / 24 ),
item = [ utc, OSApp.Dates.dhms2str( OSApp.Dates.sec2dhms( duration ) ), station, new Date( utc.getTime() + ( duration * 1000 ) ), flowRate ];
case "station":
var stationItem = [ utc, OSApp.Dates.dhms2str( OSApp.Dates.sec2dhms( duration ) ), station, new Date( utc.getTime() + ( duration * 1000 ) ), flowRate ];
sortedData[ station ].push( stationItem );
break;
case "day":
var day = Math.floor( date.getTime() / 1000 / 60 / 60 / 24 ),
item = [ utc, OSApp.Dates.dhms2str( OSApp.Dates.sec2dhms( duration ) ), station, new Date( utc.getTime() + ( duration * 1000 ) ), flowRate ];

// Item structure: [startDate, runtime, station, endDate, flowRate]
// Item structure: [startDate, runtime, station, endDate, flowRate]

if ( typeof sortedData[ day ] !== "object" ) {
sortedData[ day ] = [ item ];
Expand Down Expand Up @@ -349,13 +349,13 @@ OSApp.Logs.displayPage = function() {
wlSorted = extraData[ 0 ],
flSorted = extraData[ 1 ],
stats = extraData[ 2 ],
tableHeader = "<table class=\"table-logs-datatables\"><thead><tr>" +
"<th data-priority='1'>" + OSApp.Language._( "Station" ) + "</th>" +
"<th data-priority='2'>" + OSApp.Language._( "Runtime" ) + "</th>" +
"<th data-priority='3'>" + OSApp.Language._( "Start Time" ) + "</th>" +
"<th data-priority='4'>" + OSApp.Language._( "End Time" ) + "</th>" +
"<th data-priority='5'>" + OSApp.Language._( "Flow Rate" ) + "</th>" +
"</tr></thead><tbody>",
tableHeader = "<table class=\"table-logs-datatables\"><thead><tr>" +
"<th data-priority='1'>" + OSApp.Language._( "Station" ) + "</th>" +
"<th data-priority='2'>" + OSApp.Language._( "Runtime" ) + "</th>" +
"<th data-priority='3'>" + OSApp.Language._( "Start Time" ) + "</th>" +
"<th data-priority='4'>" + OSApp.Language._( "End Time" ) + "</th>" +
"<th data-priority='5'>" + OSApp.Language._( "Flow Rate" ) + "</th>" +
"</tr></thead><tbody>",
html = showStats( stats ) + "<div data-role='collapsible-set' data-inset='true' data-theme='b' data-collapsed-icon='arrow-d' data-expanded-icon='arrow-u'>",
i = 0,
group, ct, k;
Expand Down Expand Up @@ -419,20 +419,20 @@ OSApp.Logs.displayPage = function() {

for ( k = 0; k < sortedData[ group ].length; k++ ) {
var sid = ( grouping === 'station' ) ? group : sortedData[group][k][2];
var stationName = OSApp.Stations.getName(sid);
var stationName = stations[sid];
var runTime = sortedData[ group ][ k ][ 1 ];
var startTime = formatTime( sortedData[ group ][ k ][ 0 ], grouping ) ;
var endTime = formatTime( sortedData[ group ][ k ][ 3 ], grouping );
var fRate = sortedData[ group ][ k ][ 4 ];
var flowDisplay = ( typeof fRate === "number" ) ? fRate.toFixed( 2 ) + " L/min" : "";

groupArray[ i ] += "<tr>" +
"<td>" + stationName + "</td>" + // Station name
"<td>" + runTime + "</td>" + // Runtime
"<td>" + startTime + "</td>" + // Startdate
"<td>" + endTime + "</td>" + // Enddate
"<td>" + flowDisplay + "</td>" + // Flow rate
"</tr>";
var endTime = formatTime( sortedData[ group ][ k ][ 3 ], grouping );
var fRate = sortedData[ group ][ k ][ 4 ];
var flowDisplay = ( typeof fRate === "number" ) ? fRate.toFixed( 2 ) + " L/min" : "";

groupArray[ i ] += "<tr>" +
"<td>" + stationName + "</td>" + // Station name
"<td>" + runTime + "</td>" + // Runtime
"<td>" + startTime + "</td>" + // Startdate
"<td>" + endTime + "</td>" + // Enddate
"<td>" + flowDisplay + "</td>" + // Flow rate
"</tr>";
}
groupArray[ i ] += "</tbody></table></div>";

Expand Down
33 changes: 30 additions & 3 deletions www/js/modules/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ OSApp.Options.showOptions = function( expandItem ) {
return true;
case "o49":
opt.o49 = data & 0xff;
opt.o64 = ( data >> 8 ) & 0xff;
opt.o65 = ( data >> 8 ) & 0xff;
return true;
case "o31":
if ( parseInt( data ) === 3 && !OSApp.Utils.unescapeJSON( $( "#wto" )[ 0 ].value ).baseETo ) {
Expand Down Expand Up @@ -233,6 +233,13 @@ OSApp.Options.showOptions = function( expandItem ) {
return true;
}
break;
case "tpdv":
var v = parseFloat( data );
if ( isNaN( v ) ) {
v = 0;
}
opt.tpdv = Math.round( v * 10 );
return true;
case "o18":
case "o37":
if ( parseInt( data ) > ( parseInt( page.find( "#o15" ).val() ) + 1 ) * 8 ) {
Expand Down Expand Up @@ -335,7 +342,15 @@ OSApp.Options.showOptions = function( expandItem ) {
timezones, tz, i;

page.find( ".submit" ).on( "click", submitOptions );

// Snap Target PD Voltage slider to 0 or ≥5.0 V
page.on("input change", "#tpdv", function() {
let v = parseFloat(this.value);
if (v > 0 && v < 5) {
// Decide which side to snap to: closer to 0 or 5
this.value = (v < 2.5) ? 0 : 5.0;
$(this).slider("refresh"); // update the UI
}
});
list = "<fieldset data-role='collapsible'" + ( typeof expandItem !== "string" || expandItem === "system" ? " data-collapsed='false'" : "" ) + ">" +
"<legend>" + OSApp.Language._( "System" ) + "</legend>";

Expand Down Expand Up @@ -845,6 +860,18 @@ OSApp.Options.showOptions = function( expandItem ) {
"</label><button data-mini='true' id='o30' value='" + OSApp.currentSession.controller.options.bst + "'>" + OSApp.currentSession.controller.options.bst + "ms</button></div>";
}

if ( OSApp.Firmware.checkOSVersion( 2214 ) && typeof OSApp.currentSession.controller.options.tpdv !== "undefined" && typeof OSApp.currentSession.controller.settings.apdv !== "undefined" && OSApp.currentSession.controller.settings.apdv > 0) {
list += "<div class='ui-field-contain'><label for='tpdv'>" + OSApp.Language._( "Target PD Voltage" ) +
"<button data-helptext='" +
OSApp.Language._( "The holding current of your solenoid multiplied by its coil resistance (e.g. 0.25A×30Ω=7.5V). Set to 0 to use system default." ) +
"' class='help-icon btn-no-border ui-btn ui-icon-info ui-btn-icon-notext'></button>" +
( typeof OSApp.currentSession.controller.settings.apdv !== "undefined" ?
"<br><span class='nobr'>(" + OSApp.Language._( "Actual" ) + ": " + ( OSApp.currentSession.controller.settings.apdv / 10 ).toFixed(1) + " V)</span>" :
"" ) +
"</label>" +
"<input type='range' id='tpdv' min='0' max='21' step='0.1' data-highlight='true' value='" + ( OSApp.currentSession.controller.options.tpdv / 10 ) + "'></div>";
}

if ( OSApp.Firmware.checkOSVersion( 2213 ) && typeof OSApp.currentSession.controller.options.imin !== "undefined" ) {
list += "<div class='ui-field-contain'><label for='imin'>" + OSApp.Language._( "Undercurrent Threshold" ) +
"<button data-helptext='" +
Expand Down Expand Up @@ -1733,7 +1760,7 @@ OSApp.Options.showOptions = function( expandItem ) {
"<label for='server' style='padding-top:10px'>" + OSApp.Language._( "Broker/Server" ) + "</label>" +
"</div>" +
"<div class='ui-block-b' style='width:60%'>" +
"<input class='mqtt-input' type='text' id='server' data-mini='true' maxlength='50' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false'" +
"<input class='mqtt-input' type='text' id='server' data-mini='true' maxlength='64' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false'" +
( options.en ? "" : "disabled='disabled'" ) + " placeholder='" + OSApp.Language._( "broker" ) + "' value='" + options.host + "' required />" +
"</div>" +
"<div class='ui-block-a' style='width:40%'>" +
Expand Down
Loading