mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-04-05 05:50:56 +00:00
Added automatic IP detection to setup
This commit is contained in:
2
lib/SvelteUi/app/dist/index.css
vendored
2
lib/SvelteUi/app/dist/index.css
vendored
File diff suppressed because one or more lines are too long
12
lib/SvelteUi/app/dist/index.js
vendored
12
lib/SvelteUi/app/dist/index.js
vendored
File diff suppressed because one or more lines are too long
@@ -162,41 +162,77 @@ export function getPriceSourceUrl(code) {
|
||||
|
||||
let tries = 0;
|
||||
export function scanForDevice(sysinfo, updateFn) {
|
||||
var url = "";
|
||||
tries++;
|
||||
|
||||
var retry = function() {
|
||||
const targets = buildScanTargets(sysinfo);
|
||||
if(!targets.length) {
|
||||
if(updateFn) updateFn("");
|
||||
setTimeout(scanForDevice, 1500, sysinfo, updateFn);
|
||||
return;
|
||||
}
|
||||
|
||||
const target = targets[(tries - 1) % targets.length];
|
||||
if(!target) {
|
||||
setTimeout(scanForDevice, 1000, sysinfo, updateFn);
|
||||
return;
|
||||
}
|
||||
|
||||
const url = normalizeTarget(target);
|
||||
if(console) console.log("Trying url " + url);
|
||||
if(updateFn) updateFn(url);
|
||||
|
||||
const retry = function() {
|
||||
setTimeout(scanForDevice, 1000, sysinfo, updateFn);
|
||||
};
|
||||
|
||||
if(sysinfo.net.ip && tries%3 == 0) {
|
||||
if(!sysinfo.net.ip) {
|
||||
retry();
|
||||
return;
|
||||
};
|
||||
url = "http://" + sysinfo.net.ip;
|
||||
} else if(sysinfo.hostname && tries%3 == 1) {
|
||||
url = "http://" + sysinfo.hostname;
|
||||
} else if(sysinfo.hostname && tries%3 == 2) {
|
||||
url = "http://" + sysinfo.hostname + ".local";
|
||||
} else {
|
||||
url = "";
|
||||
}
|
||||
if(console) console.log("Trying url " + url);
|
||||
if(updateFn) updateFn(url);
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.timeout = 5000;
|
||||
xhr.addEventListener('abort', retry);
|
||||
xhr.addEventListener('error', retry);
|
||||
xhr.addEventListener('timeout', retry);
|
||||
xhr.addEventListener('load', function(e) {
|
||||
xhr.addEventListener('load', function() {
|
||||
window.location.href = url ? url : "/";
|
||||
});
|
||||
xhr.open("GET", url + "/is-alive", true);
|
||||
const healthUrl = url.replace(/\/$/, '') + "/is-alive";
|
||||
xhr.open("GET", healthUrl, true);
|
||||
xhr.send();
|
||||
};
|
||||
|
||||
function buildScanTargets(sysinfo = {}) {
|
||||
const manualTargets = Array.isArray(sysinfo.targets) ? sysinfo.targets : [];
|
||||
const fallbackTargets = [];
|
||||
|
||||
if(sysinfo.net && sysinfo.net.ip) {
|
||||
fallbackTargets.push(sysinfo.net.ip);
|
||||
}
|
||||
if(sysinfo.hostname) {
|
||||
fallbackTargets.push(sysinfo.hostname);
|
||||
const looksLikeHost = sysinfo.hostname.indexOf('.') === -1 && sysinfo.hostname.indexOf(':') === -1;
|
||||
if(looksLikeHost) {
|
||||
fallbackTargets.push(`${sysinfo.hostname}.local`);
|
||||
}
|
||||
}
|
||||
|
||||
const candidates = [...manualTargets, ...fallbackTargets];
|
||||
const deduped = [];
|
||||
for(const value of candidates) {
|
||||
if(!value) continue;
|
||||
const trimmed = value.toString().trim();
|
||||
if(!trimmed) continue;
|
||||
if(!deduped.includes(trimmed)) deduped.push(trimmed);
|
||||
}
|
||||
return deduped;
|
||||
}
|
||||
|
||||
function normalizeTarget(target) {
|
||||
if(!target) return "";
|
||||
const trimmed = target.toString().trim();
|
||||
if(trimmed.startsWith("http://") || trimmed.startsWith("https://")) {
|
||||
return trimmed;
|
||||
}
|
||||
return `http://${trimmed}`;
|
||||
}
|
||||
|
||||
export function capitalize(s) {
|
||||
return s.charAt(0).toUpperCase() + s.slice(1);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script>
|
||||
import { sysinfoStore, networksStore } from './DataStores.js';
|
||||
import { get } from 'svelte/store';
|
||||
import { translationsStore } from './TranslationService.js';
|
||||
import Mask from './Mask.svelte'
|
||||
import SubnetOptions from './SubnetOptions.svelte';
|
||||
@@ -29,6 +30,7 @@
|
||||
let staticIp = false;
|
||||
let connectionMode = 1;
|
||||
let loadingOrSaving = false;
|
||||
let reconnectTargets = [];
|
||||
|
||||
function updateSysinfo(url) {
|
||||
sysinfoStore.update(s => {
|
||||
@@ -53,19 +55,41 @@
|
||||
let res = (await response.json())
|
||||
loadingOrSaving = false;
|
||||
|
||||
const hostFromForm = (formData.get('sh') ?? '').trim();
|
||||
const message = typeof res.message === 'string' ? res.message : '';
|
||||
const hintParts = message.split('|').map(part => part.trim());
|
||||
const hintHost = hintParts[0] ?? '';
|
||||
const hintMdns = hintParts[1] ?? '';
|
||||
const hintIp = hintParts[2] ?? '';
|
||||
const fallbackHostname = hintHost || hostFromForm || sysinfo.hostname || (sysinfo?.chipId ? `ams-${sysinfo.chipId}` : 'ams-reader');
|
||||
const fallbackMdns = hintMdns || (fallbackHostname && fallbackHostname.indexOf('.') === -1 && fallbackHostname.indexOf(':') === -1 ? `${fallbackHostname}.local` : fallbackHostname);
|
||||
const staticIpValue = staticIp ? (formData.get('si') || '').trim() : hintIp;
|
||||
const uniqueTargets = Array.from(new Set([staticIpValue, fallbackHostname, fallbackMdns].filter(val => val && val.length > 0)));
|
||||
reconnectTargets = res.reboot ? [...uniqueTargets] : [];
|
||||
|
||||
sysinfoStore.update(s => {
|
||||
s.hostname = formData.get('sh');
|
||||
s.usrcfg = res.success;
|
||||
s.booting = res.reboot;
|
||||
if(!s.net) s.net = {};
|
||||
const computedHostname = fallbackHostname || s.hostname || hostFromForm;
|
||||
s.hostname = computedHostname;
|
||||
if(staticIp) {
|
||||
s.net.ip = formData.get('si');
|
||||
s.net.ip = staticIpValue;
|
||||
s.net.mask = formData.get('su');
|
||||
s.net.gw = formData.get('sg');
|
||||
s.net.dns1 = formData.get('sd');
|
||||
} else if(hintIp) {
|
||||
s.net.ip = hintIp;
|
||||
}
|
||||
if(res.reboot) setTimeout(scanForDevice, 5000, sysinfo, updateSysinfo);
|
||||
s.targets = [...uniqueTargets];
|
||||
s.usrcfg = res.success;
|
||||
s.booting = res.reboot;
|
||||
return s;
|
||||
});
|
||||
|
||||
const latestSysinfo = get(sysinfoStore);
|
||||
sysinfo = latestSysinfo;
|
||||
if(res.reboot) {
|
||||
setTimeout(() => scanForDevice(latestSysinfo, updateSysinfo), 5000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -169,6 +193,16 @@
|
||||
<div class="my-3">
|
||||
<button type="submit" class="btn-pri">{translations.btn?.save ?? "Save"}</button>
|
||||
</div>
|
||||
{#if reconnectTargets.length}
|
||||
<div class="mt-4 text-sm text-gray-600 dark:text-gray-300">
|
||||
<p>{translations.setup?.reconnect?.info ?? "Device will reboot now. Try these addresses to reconnect:"}</p>
|
||||
<ul class="list-disc pl-5 space-y-1 mt-2">
|
||||
{#each reconnectTargets as target}
|
||||
<li><code>{target.startsWith('http://') || target.startsWith('https://') ? target : `http://${target}`}</code></li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
{/if}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -174,6 +174,7 @@ private:
|
||||
|
||||
void addConditionalCloudHeaders();
|
||||
void optionsGet();
|
||||
bool probeNewNetworkIp(NetworkConfig& network, String& ipOut);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -348,7 +348,11 @@ void AmsWebServer::sysinfoJson() {
|
||||
if(sys.userConfigured) {
|
||||
NetworkConfig networkConfig;
|
||||
config->getNetworkConfig(networkConfig);
|
||||
hostname = String(networkConfig.hostname);
|
||||
if(strlen(networkConfig.hostname) > 0) {
|
||||
hostname = String(networkConfig.hostname);
|
||||
} else {
|
||||
hostname = "ams-"+chipIdStr;
|
||||
}
|
||||
} else {
|
||||
hostname = "ams-"+chipIdStr;
|
||||
}
|
||||
@@ -1239,6 +1243,18 @@ void AmsWebServer::handleSave() {
|
||||
SystemConfig sys;
|
||||
config->getSystemConfig(sys);
|
||||
|
||||
uint32_t chipId;
|
||||
#if defined(ESP32)
|
||||
chipId = ( ESP.getEfuseMac() >> 32 ) % 0xFFFFFFFF;
|
||||
#else
|
||||
chipId = ESP.getChipId();
|
||||
#endif
|
||||
String chipIdStr = String(chipId, HEX);
|
||||
String defaultHostname = F("ams-");
|
||||
defaultHostname += chipIdStr;
|
||||
String reconnectHost = "";
|
||||
String reconnectIp = "";
|
||||
|
||||
bool success = true;
|
||||
if(server.hasArg(F("v")) && server.arg(F("v")) == F("true")) {
|
||||
int boardType = server.arg(F("vb")).toInt();
|
||||
@@ -1276,17 +1292,25 @@ void AmsWebServer::handleSave() {
|
||||
network.mode = server.arg(F("sc")).toInt();
|
||||
if(network.mode > 3 || network.mode == 0) network.mode = 1; // WiFi Client
|
||||
|
||||
String requestedHostname = server.hasArg(F("sh")) ? server.arg(F("sh")) : String("");
|
||||
requestedHostname.trim();
|
||||
|
||||
if(network.mode == 3 || strlen(network.ssid) > 0) {
|
||||
if(server.hasArg(F("sm")) && server.arg(F("sm")) == "static") {
|
||||
strcpy(network.ip, server.arg(F("si")).c_str());
|
||||
String ipValue = server.arg(F("si"));
|
||||
strcpy(network.ip, ipValue.c_str());
|
||||
reconnectIp = ipValue;
|
||||
strcpy(network.gateway, server.arg(F("sg")).c_str());
|
||||
strcpy(network.subnet, server.arg(F("su")).c_str());
|
||||
strcpy(network.dns1, server.arg(F("sd")).c_str());
|
||||
} else {
|
||||
reconnectIp = "";
|
||||
}
|
||||
|
||||
if(server.hasArg(F("sh")) && !server.arg(F("sh")).isEmpty()) {
|
||||
strcpy(network.hostname, server.arg(F("sh")).c_str());
|
||||
if(requestedHostname.length() > 0) {
|
||||
strcpy(network.hostname, requestedHostname.c_str());
|
||||
network.mdns = true;
|
||||
reconnectHost = requestedHostname;
|
||||
} else {
|
||||
network.mdns = false;
|
||||
}
|
||||
@@ -1318,6 +1342,12 @@ void AmsWebServer::handleSave() {
|
||||
#endif
|
||||
config->setNetworkConfig(network);
|
||||
config->setMeterConfig(meterConfig);
|
||||
if(reconnectIp.length() == 0) {
|
||||
probeNewNetworkIp(network, reconnectIp);
|
||||
}
|
||||
if(reconnectHost.length() == 0 && sys.vendorConfigured) {
|
||||
reconnectHost = defaultHostname;
|
||||
}
|
||||
|
||||
sys.userConfigured = success;
|
||||
sys.dataCollectionConsent = 0;
|
||||
@@ -1394,22 +1424,28 @@ void AmsWebServer::handleSave() {
|
||||
|
||||
if(server.hasArg(F("nm"))) {
|
||||
if(server.arg(F("nm")) == "static") {
|
||||
strcpy(network.ip, server.arg(F("ni")).c_str());
|
||||
String ipValue = server.arg(F("ni"));
|
||||
strcpy(network.ip, ipValue.c_str());
|
||||
strcpy(network.gateway, server.arg(F("ng")).c_str());
|
||||
strcpy(network.subnet, server.arg(F("ns")).c_str());
|
||||
strcpy(network.dns1, server.arg(F("nd1")).c_str());
|
||||
strcpy(network.dns2, server.arg(F("nd2")).c_str());
|
||||
reconnectIp = ipValue;
|
||||
} else if(server.arg(F("nm")) == "dhcp") {
|
||||
strcpy(network.ip, "");
|
||||
strcpy(network.gateway, "");
|
||||
strcpy(network.subnet, "");
|
||||
strcpy(network.dns1, "");
|
||||
strcpy(network.dns2, "");
|
||||
reconnectIp = "";
|
||||
}
|
||||
}
|
||||
network.ipv6 = server.hasArg(F("nx")) && server.arg(F("nx")) == F("true");
|
||||
network.mdns = server.hasArg(F("nd")) && server.arg(F("nd")) == F("true");
|
||||
config->setNetworkConfig(network);
|
||||
if(strlen(network.hostname) > 0) {
|
||||
reconnectHost = network.hostname;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1505,6 +1541,15 @@ void AmsWebServer::handleSave() {
|
||||
strcpy(network.hostname, server.arg(F("gh")).c_str());
|
||||
}
|
||||
config->setNetworkConfig(network);
|
||||
if(server.hasArg(F("gh"))) {
|
||||
String hostArg = server.arg(F("gh"));
|
||||
hostArg.trim();
|
||||
if(hostArg.length() > 0) {
|
||||
reconnectHost = hostArg;
|
||||
}
|
||||
} else if(strlen(network.hostname) > 0) {
|
||||
reconnectHost = network.hostname;
|
||||
}
|
||||
|
||||
NtpConfig ntp;
|
||||
config->getNtpConfig(ntp);
|
||||
@@ -1738,9 +1783,36 @@ void AmsWebServer::handleSave() {
|
||||
success = false;
|
||||
}
|
||||
|
||||
NetworkConfig currentNetwork;
|
||||
config->getNetworkConfig(currentNetwork);
|
||||
if(reconnectHost.length() == 0 && strlen(currentNetwork.hostname) > 0) {
|
||||
reconnectHost = String(currentNetwork.hostname);
|
||||
}
|
||||
if(reconnectHost.length() == 0) {
|
||||
reconnectHost = defaultHostname;
|
||||
}
|
||||
reconnectHost.trim();
|
||||
if(reconnectIp.length() == 0 && strlen(currentNetwork.ip) > 0) {
|
||||
reconnectIp = String(currentNetwork.ip);
|
||||
}
|
||||
String reconnectMdns = reconnectHost;
|
||||
reconnectMdns.trim();
|
||||
if(reconnectMdns.length() > 0) {
|
||||
bool appearsToBeHostName = reconnectMdns.indexOf('.') == -1 && reconnectMdns.indexOf(':') == -1;
|
||||
if(!reconnectMdns.endsWith(F(".local")) && appearsToBeHostName) {
|
||||
reconnectMdns += F(".local");
|
||||
}
|
||||
}
|
||||
String reconnectHint = reconnectHost;
|
||||
String mdnsForHint = reconnectMdns.length() > 0 ? reconnectMdns : reconnectHost;
|
||||
reconnectHint += F("|");
|
||||
reconnectHint += mdnsForHint;
|
||||
reconnectHint += F("|");
|
||||
reconnectHint += reconnectIp;
|
||||
|
||||
snprintf_P(buf, BufferSize, RESPONSE_JSON,
|
||||
success ? "true" : "false",
|
||||
"",
|
||||
reconnectHint.c_str(),
|
||||
performRestart ? "true" : "false"
|
||||
);
|
||||
server.setContentLength(strlen(buf));
|
||||
@@ -2830,6 +2902,54 @@ void AmsWebServer::optionsGet() {
|
||||
server.send(200);
|
||||
}
|
||||
|
||||
bool AmsWebServer::probeNewNetworkIp(NetworkConfig& network, String& ipOut) {
|
||||
if(network.mode != NETWORK_MODE_WIFI_CLIENT || strlen(network.ssid) == 0) {
|
||||
return false;
|
||||
}
|
||||
if(ipOut.length() > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
#if defined(ESP8266)
|
||||
WiFiMode_t originalMode = WiFi.getMode();
|
||||
#else
|
||||
wifi_mode_t originalMode = WiFi.getMode();
|
||||
#endif
|
||||
if(originalMode != WIFI_AP_STA) {
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
}
|
||||
WiFi.persistent(false);
|
||||
if(strlen(network.hostname) > 0) {
|
||||
#if defined(ESP32)
|
||||
WiFi.setHostname(network.hostname);
|
||||
#else
|
||||
WiFi.hostname(network.hostname);
|
||||
#endif
|
||||
}
|
||||
WiFi.begin(network.ssid, strlen(network.psk) > 0 ? network.psk : NULL);
|
||||
unsigned long start = millis();
|
||||
while(millis() - start < 8000) {
|
||||
wl_status_t status = WiFi.status();
|
||||
if(status == WL_CONNECTED) {
|
||||
IPAddress candidate = WiFi.localIP();
|
||||
if(candidate != IPAddress()) {
|
||||
ipOut = candidate.toString();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
server.handleClient();
|
||||
delay(120);
|
||||
yield();
|
||||
}
|
||||
WiFi.disconnect(false);
|
||||
WiFi.mode(originalMode);
|
||||
#endif
|
||||
return found;
|
||||
}
|
||||
|
||||
void AmsWebServer::wifiScan() {
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user