mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-03-12 21:44:21 +00:00
Compare commits
6 Commits
feat/setup
...
upgrade/sv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d128700c1 | ||
|
|
6743750d8f | ||
|
|
640e957065 | ||
|
|
d4f11c0412 | ||
|
|
01acc6d6e8 | ||
|
|
e89bb53941 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -51,7 +51,7 @@ jobs:
|
||||
- name: Set up node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '19.x'
|
||||
node-version: '22.x'
|
||||
- name: Build with node
|
||||
run: |
|
||||
cd lib/SvelteUi/app
|
||||
|
||||
2
.github/workflows/release-deploy-env.yml
vendored
2
.github/workflows/release-deploy-env.yml
vendored
@@ -73,7 +73,7 @@ jobs:
|
||||
- name: Set up node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '19.x'
|
||||
node-version: '22.x'
|
||||
- name: Build with node
|
||||
run: |
|
||||
cd lib/SvelteUi/app
|
||||
|
||||
@@ -19,7 +19,6 @@ bool WiFiAccessPointConnectionHandler::connect(NetworkConfig config, SystemConfi
|
||||
//wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, 0); // Disable default gw
|
||||
|
||||
WiFi.mode(WIFI_AP);
|
||||
WiFi.persistent(false);
|
||||
WiFi.softAP(config.ssid, config.psk);
|
||||
|
||||
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
|
||||
|
||||
@@ -100,7 +100,6 @@ bool WiFiClientConnectionHandler::connect(NetworkConfig config, SystemConfig sys
|
||||
}
|
||||
#endif
|
||||
WiFi.setAutoReconnect(true);
|
||||
WiFi.persistent(false);
|
||||
this->config = config;
|
||||
#if defined(ESP32)
|
||||
if(begin(config.ssid, config.psk)) {
|
||||
|
||||
59
lib/SvelteUi/app/README.md
Normal file
59
lib/SvelteUi/app/README.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# SvelteUi App
|
||||
|
||||
Web interface for AMS Reader firmware built with Svelte 5 and Vite 6.
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Prerequisites
|
||||
- Node.js 20.x or 22.x LTS (required for Vite 6)
|
||||
- npm
|
||||
|
||||
### Local Development Configuration
|
||||
|
||||
To develop against your AMS reader device, you need to configure the proxy target:
|
||||
|
||||
1. Copy the example config file:
|
||||
```bash
|
||||
cp vite.config.local.example.js vite.config.local.js
|
||||
```
|
||||
|
||||
2. Edit `vite.config.local.js` and update the IP address to match your device:
|
||||
```javascript
|
||||
export default {
|
||||
proxyTarget: "http://192.168.1.100" // Your device's IP
|
||||
}
|
||||
```
|
||||
|
||||
3. The `vite.config.local.js` file is gitignored, so your personal settings won't be committed.
|
||||
|
||||
### Running Development Server
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
The dev server will proxy API requests to your configured device IP.
|
||||
|
||||
### Building for Production
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
The build output will be in the `dist/` directory.
|
||||
|
||||
## Project Structure
|
||||
|
||||
- `src/` - Application source code
|
||||
- `routes/` - Page components using svelte-spa-router
|
||||
- `lib/` - Shared components and utilities
|
||||
- `public/` - Static assets (favicon, etc.)
|
||||
- `dist/` - Build output (not committed to git)
|
||||
|
||||
## Key Technologies
|
||||
|
||||
- **Svelte 5.17.0** - UI framework
|
||||
- **Vite 6.0.7** - Build tool
|
||||
- **svelte-spa-router 4.0.1** - Hash-based routing
|
||||
- **Tailwind CSS** - Styling
|
||||
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
3
lib/SvelteUi/app/dist/index.html
vendored
3
lib/SvelteUi/app/dist/index.html
vendored
@@ -8,10 +8,9 @@
|
||||
<link rel="mask-icon" href="/favicon.svg" color="#000000">
|
||||
<title>AMS reader</title>
|
||||
<script type="module" crossorigin src="/index.js"></script>
|
||||
<link rel="stylesheet" href="/index.css">
|
||||
<link rel="stylesheet" crossorigin href="/index.css">
|
||||
</head>
|
||||
<body class="bg-gray-100 dark:bg-gray-900">
|
||||
<div id="app"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
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
2891
lib/SvelteUi/app/package-lock.json
generated
2891
lib/SvelteUi/app/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,28 +9,22 @@
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"overrides": {
|
||||
"svelte-navigator": {
|
||||
"svelte": ">=4.x"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^2.1.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.2",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"http-proxy-middleware": "^2.0.9",
|
||||
"postcss": "^8.4.31",
|
||||
"postcss-load-config": "^4.0.1",
|
||||
"svelte": "^4.2.19",
|
||||
"svelte-navigator": "^3.2.2",
|
||||
"svelte-preprocess": "^5.0.3",
|
||||
"svelte": "^5.17.0",
|
||||
"svelte-spa-router": "^4.0.1",
|
||||
"svelte-preprocess": "^6.0.3",
|
||||
"svelte-qrcode": "^1.0.0",
|
||||
"tailwindcss": "^3.3.1",
|
||||
"vite": "^4.5.14"
|
||||
"vite": "^6.0.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"cssnano": "^5.1.15",
|
||||
"esbuild": ">=0.25.0",
|
||||
"ipaddr.js": "^2.3.0"
|
||||
"esbuild": ">=0.25.0"
|
||||
}
|
||||
}
|
||||
|
||||
19
lib/SvelteUi/app/public/favicon.svg
Normal file
19
lib/SvelteUi/app/public/favicon.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52">
|
||||
<title>Amsleser</title>
|
||||
<g transform="translate(-29.5,-83)">
|
||||
<circle r="4.8016944" cy="123.56455" cx="55.064552"
|
||||
style="fill:none;stroke:#045c7c;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path d="m 41.298717,103.9049 a 24,24 0 0 1 27.531669,0"
|
||||
style="fill:none;stroke:#045c7c;stroke-width:3.3;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path d="m 35.562952,95.713384 a 34,34 0 0 1 39.003199,-2e-6"
|
||||
style="fill:none;stroke:#045c7c;stroke-width:3.3;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path d="m 47.034482,112.09642 a 14,14 0 0 1 16.06014,0"
|
||||
style="fill:none;stroke:#045c7c;stroke-width:3.3;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<circle r="3" cy="105.99158" cx="38.181862"
|
||||
style="fill:none;stroke:#045c7c;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<circle r="3" cy="97.959579" cx="77.491386"
|
||||
style="fill:none;stroke:#045c7c;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -1,49 +1,27 @@
|
||||
<script>
|
||||
import { Router, Route, navigate } from "svelte-navigator";
|
||||
import { getTariff, tariffStore, sysinfoStore, dataStore, importPricesStore, exportPricesStore, dayPlotStore, monthPlotStore, temperaturesStore, getSysinfo } from './lib/DataStores.js';
|
||||
import Router from "svelte-spa-router";
|
||||
import { push } from "svelte-spa-router";
|
||||
import { getTariff, sysinfoStore, dataStore, getSysinfo } from './lib/DataStores.js';
|
||||
import { translationsStore, getTranslations } from "./lib/TranslationService.js";
|
||||
import Favicon from './assets/favicon.svg'; // Need this for the build
|
||||
import Header from './lib/Header.svelte';
|
||||
import Dashboard from './lib/Dashboard.svelte';
|
||||
import ConfigurationPanel from './lib/ConfigurationPanel.svelte';
|
||||
import StatusPage from './lib/StatusPage.svelte';
|
||||
import VendorPanel from './lib/VendorPanel.svelte';
|
||||
import SetupPanel from './lib/SetupPanel.svelte';
|
||||
import DashboardRoute from './routes/DashboardRoute.svelte';
|
||||
import ConfigurationRoute from './routes/ConfigurationRoute.svelte';
|
||||
import StatusRoute from './routes/StatusRoute.svelte';
|
||||
import PriceConfigRoute from './routes/PriceConfigRoute.svelte';
|
||||
import MqttCaRoute from './routes/MqttCaRoute.svelte';
|
||||
import MqttCertRoute from './routes/MqttCertRoute.svelte';
|
||||
import MqttKeyRoute from './routes/MqttKeyRoute.svelte';
|
||||
import ConsentRoute from './routes/ConsentRoute.svelte';
|
||||
import SetupRoute from './routes/SetupRoute.svelte';
|
||||
import VendorRoute from './routes/VendorRoute.svelte';
|
||||
import EditDayRoute from './routes/EditDayRoute.svelte';
|
||||
import EditMonthRoute from './routes/EditMonthRoute.svelte';
|
||||
import Mask from './lib/Mask.svelte';
|
||||
import FileUploadComponent from "./lib/FileUploadComponent.svelte";
|
||||
import ConsentComponent from "./lib/ConsentComponent.svelte";
|
||||
import PriceConfig from "./lib/PriceConfig.svelte";
|
||||
import DataEdit from "./lib/DataEdit.svelte";
|
||||
import { updateRealtime } from "./lib/RealtimeStore.js";
|
||||
|
||||
let basepath = document.getElementsByTagName('base')[0].getAttribute("href");
|
||||
if(!basepath) basepath = "/";
|
||||
|
||||
let importPrices;
|
||||
importPricesStore.subscribe(update => {
|
||||
importPrices = update;
|
||||
});
|
||||
|
||||
let exportPrices;
|
||||
exportPricesStore.subscribe(update => {
|
||||
exportPrices = update;
|
||||
});
|
||||
|
||||
let dayPlot;
|
||||
dayPlotStore.subscribe(update => {
|
||||
dayPlot = update;
|
||||
});
|
||||
|
||||
let monthPlot;
|
||||
monthPlotStore.subscribe(update => {
|
||||
monthPlot = update;
|
||||
});
|
||||
|
||||
let temperatures;
|
||||
temperaturesStore.subscribe(update => {
|
||||
temperatures = update;
|
||||
});
|
||||
|
||||
let translations = {};
|
||||
translationsStore.subscribe(update => {
|
||||
translations = update;
|
||||
@@ -56,11 +34,11 @@
|
||||
sysinfoStore.subscribe(update => {
|
||||
sysinfo = update;
|
||||
if(sysinfo.vndcfg === false) {
|
||||
navigate(basepath + "vendor");
|
||||
push("/vendor");
|
||||
} else if(sysinfo.usrcfg === false) {
|
||||
navigate(basepath + "setup");
|
||||
push("/setup");
|
||||
} else if(sysinfo.fwconsent === 0) {
|
||||
navigate(basepath + "consent");
|
||||
push("/consent");
|
||||
}
|
||||
|
||||
if(sysinfo.ui.k === 1) {
|
||||
@@ -94,53 +72,26 @@
|
||||
updateRealtime(update);
|
||||
});
|
||||
|
||||
let tariffData = {};
|
||||
tariffStore.subscribe(update => {
|
||||
tariffData = update;
|
||||
});
|
||||
getTariff();
|
||||
</script>
|
||||
|
||||
<div class="container mx-auto m-3">
|
||||
<Router basepath={basepath}>
|
||||
<Header data={data} basepath={basepath}/>
|
||||
<Route path="/">
|
||||
<Dashboard data={data} sysinfo={sysinfo} importPrices={importPrices} exportPrices={exportPrices} dayPlot={dayPlot} monthPlot={monthPlot} temperatures={temperatures} translations={translations} tariffData={tariffData}/>
|
||||
</Route>
|
||||
<Route path="/configuration">
|
||||
<ConfigurationPanel sysinfo={sysinfo} basepath={basepath} data={data}/>
|
||||
</Route>
|
||||
<Route path="/priceconfig">
|
||||
<PriceConfig basepath={basepath}/>
|
||||
</Route>
|
||||
<Route path="/status">
|
||||
<StatusPage sysinfo={sysinfo} data={data}/>
|
||||
</Route>
|
||||
<Route path="/mqtt-ca">
|
||||
<FileUploadComponent title="CA" action="/mqtt-ca"/>
|
||||
</Route>
|
||||
<Route path="/mqtt-cert">
|
||||
<FileUploadComponent title="certificate" action="/mqtt-cert"/>
|
||||
</Route>
|
||||
<Route path="/mqtt-key">
|
||||
<FileUploadComponent title="private key" action="/mqtt-key"/>
|
||||
</Route>
|
||||
<Route path="/consent">
|
||||
<ConsentComponent sysinfo={sysinfo} basepath={basepath}/>
|
||||
</Route>
|
||||
<Route path="/setup">
|
||||
<SetupPanel sysinfo={sysinfo}/>
|
||||
</Route>
|
||||
<Route path="/vendor">
|
||||
<VendorPanel sysinfo={sysinfo} basepath={basepath}/>
|
||||
</Route>
|
||||
<Route path="/edit-day">
|
||||
<DataEdit prefix="UTC Hour" data={dayPlot} url="/dayplot" basepath={basepath}/>
|
||||
</Route>
|
||||
<Route path="/edit-month">
|
||||
<DataEdit prefix="Day" data={monthPlot} url="/monthplot" basepath={basepath}/>
|
||||
</Route>
|
||||
</Router>
|
||||
<Header data={data} basepath={basepath}/>
|
||||
|
||||
<Router routes={{
|
||||
'/': DashboardRoute,
|
||||
'/configuration': ConfigurationRoute,
|
||||
'/priceconfig': PriceConfigRoute,
|
||||
'/status': StatusRoute,
|
||||
'/mqtt-ca': MqttCaRoute,
|
||||
'/mqtt-cert': MqttCertRoute,
|
||||
'/mqtt-key': MqttKeyRoute,
|
||||
'/consent': ConsentRoute,
|
||||
'/setup': SetupRoute,
|
||||
'/vendor': VendorRoute,
|
||||
'/edit-day': EditDayRoute,
|
||||
'/edit-month': EditMonthRoute,
|
||||
}} />
|
||||
|
||||
{#if sysinfo.booting}
|
||||
{#if sysinfo.trying}
|
||||
|
||||
@@ -206,8 +206,4 @@ svg {
|
||||
border-width: 9px;
|
||||
border-style: solid;
|
||||
border-color: #ddd transparent transparent transparent;
|
||||
}
|
||||
|
||||
.link {
|
||||
@apply cursor-pointer;
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
<script>
|
||||
import { Link } from "svelte-navigator";
|
||||
import { tooltip } from './tooltip';
|
||||
|
||||
export let config;
|
||||
@@ -47,7 +46,7 @@
|
||||
{#if config.link}
|
||||
<div class="text-xs text-right">
|
||||
{#if config.link.route}
|
||||
<Link to={config.link.url}>{config.link.text}</Link>
|
||||
<a href={"#" + config.link.url}>{config.link.text}</a>
|
||||
{:else}
|
||||
<a href={config.link.url} target={config.link.target}>{config.link.text}</a>
|
||||
{/if}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { translationsStore } from './TranslationService';
|
||||
import { navigate } from 'svelte-navigator';
|
||||
import { push } from 'svelte-spa-router';
|
||||
import Mask from './Mask.svelte'
|
||||
|
||||
export let prefix;
|
||||
@@ -59,7 +59,7 @@
|
||||
let res = (await response.json())
|
||||
|
||||
saving = false;
|
||||
navigate(basepath);
|
||||
push(basepath);
|
||||
}
|
||||
</script>
|
||||
<form on:submit|preventDefault={handleSubmit} autocomplete="off">
|
||||
@@ -70,7 +70,7 @@
|
||||
{#each importElements as el}
|
||||
<label class="flex w-60 m-1">
|
||||
<span class="in-pre">{el.name}</span>
|
||||
<input name="{el.key}" bind:value={data[el.key]} type="number" step="0.01" class="in-txt w-full text-right"/>
|
||||
<input name="{el.key}" bind:value={data[el.key]} type="number" step="0.001" class="in-txt w-full text-right"/>
|
||||
<span class="in-post">kWh</span>
|
||||
</label>
|
||||
{/each}
|
||||
@@ -82,7 +82,7 @@
|
||||
{#each exportElements as el}
|
||||
<label class="flex w-60 m-1">
|
||||
<span class="in-pre">{el.name}</span>
|
||||
<input name="{el.key}" bind:value={data[el.key]} type="number" step="0.01" class="in-txt w-full text-right"/>
|
||||
<input name="{el.key}" bind:value={data[el.key]} type="number" step="0.001" class="in-txt w-full text-right"/>
|
||||
<span class="in-post">kWh</span>
|
||||
</label>
|
||||
{/each}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script>
|
||||
import { Link } from "svelte-navigator";
|
||||
import { sysinfoStore } from './DataStores.js';
|
||||
import { upgrade, upgradeWarningText } from './UpgradeHelper';
|
||||
import { boardtype, isBusPowered, wiki, bcol } from './Helpers.js';
|
||||
@@ -46,7 +45,7 @@
|
||||
<nav class="hdr">
|
||||
<div class="flex flex-wrap space-x-4 text-sm text-gray-300">
|
||||
<div class="flex text-lg text-gray-100 p-2">
|
||||
<Link to="/">AMS reader <span>{sysinfo.version}</span></Link>
|
||||
<a href={basepath}>AMS reader <span>{sysinfo.version}</span></a>
|
||||
</div>
|
||||
<div class="flex-none my-auto p-2 flex space-x-4">
|
||||
<div class="flex-none my-auto"><Uptime epoch={data.u}/></div>
|
||||
@@ -79,10 +78,10 @@
|
||||
</div>
|
||||
{#if sysinfo.vndcfg && sysinfo.usrcfg}
|
||||
<div class="flex-none px-1 mt-1" title={translations.header?.config ?? ""}>
|
||||
<Link to="/configuration"><GearIcon/></Link>
|
||||
<a href="#/configuration"><GearIcon/></a>
|
||||
</div>
|
||||
<div class="flex-none px-1 mt-1" title={translations.header?.status ?? ""}>
|
||||
<Link to="/status"><InfoIcon/></Link>
|
||||
<a href="#/status"><InfoIcon/></a>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex-none px-1 mt-1" title={translations.header?.doc ?? ""}>
|
||||
|
||||
@@ -41,22 +41,22 @@
|
||||
for(i = 0; i < tariffData.p.length; i++) {
|
||||
let peak = tariffData.p[i];
|
||||
|
||||
let title = "";
|
||||
let peakTitle = "";
|
||||
let daylabel = "-";
|
||||
if(peak.d > 0) {
|
||||
daylabel = zeropad(peak.d) + ".";
|
||||
title = zeropad(peak.d) + "." + (translations.months ? translations.months?.[new Date().getMonth()] : zeropad(new Date().getMonth()+1));
|
||||
peakTitle = zeropad(peak.d) + "." + (translations.months ? translations.months?.[new Date().getMonth()] : zeropad(new Date().getMonth()+1));
|
||||
if(tariffData.p.length < 4) {
|
||||
daylabel = title;
|
||||
daylabel = peakTitle;
|
||||
}
|
||||
}
|
||||
if(!isNaN(peak.h))
|
||||
title = title + ' ' + zeropad(peak.h) + ':00';
|
||||
title = title + ': ' + peak.v.toFixed(2) + ' kWh';
|
||||
peakTitle = peakTitle + ' ' + zeropad(peak.h) + ':00';
|
||||
peakTitle = peakTitle + ': ' + peak.v.toFixed(2) + ' kWh';
|
||||
points.push({
|
||||
label: peak.v.toFixed(2),
|
||||
value: peak.v,
|
||||
title: title,
|
||||
title: peakTitle,
|
||||
color: dark ? '#5c2da5' : '#7c3aed'
|
||||
});
|
||||
xTicks.push({
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import "./app.postcss";
|
||||
import { mount } from "svelte";
|
||||
import App from "./App.svelte";
|
||||
|
||||
const app = new App({
|
||||
const app = mount(App, {
|
||||
target: document.getElementById("app"),
|
||||
});
|
||||
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
<script>
|
||||
import { getConfiguration, configurationStore } from './ConfigurationStore'
|
||||
import { sysinfoStore, networksStore } from './DataStores.js';
|
||||
import fetchWithTimeout from './fetchWithTimeout';
|
||||
import { translationsStore } from './TranslationService';
|
||||
import { wiki, ipPattern, asciiPattern, asciiPatternExt, charAndNumPattern, hexPattern, numPattern, isBusPowered } from './Helpers.js';
|
||||
import UartSelectOptions from './UartSelectOptions.svelte';
|
||||
import Mask from './Mask.svelte'
|
||||
import Badge from './Badge.svelte';
|
||||
import CountrySelectOptions from './CountrySelectOptions.svelte';
|
||||
import { Link, navigate } from 'svelte-navigator';
|
||||
import SubnetOptions from './SubnetOptions.svelte';
|
||||
import { getConfiguration, configurationStore } from '../lib/ConfigurationStore'
|
||||
import { sysinfoStore, networksStore, dataStore } from '../lib/DataStores.js';
|
||||
import fetchWithTimeout from '../lib/fetchWithTimeout';
|
||||
import { translationsStore } from '../lib/TranslationService';
|
||||
import { wiki, ipPattern, asciiPattern, asciiPatternExt, charAndNumPattern, hexPattern, numPattern, isBusPowered } from '../lib/Helpers.js';
|
||||
import UartSelectOptions from '../lib/UartSelectOptions.svelte';
|
||||
import Mask from '../lib/Mask.svelte'
|
||||
import Badge from '../lib/Badge.svelte';
|
||||
import CountrySelectOptions from '../lib/CountrySelectOptions.svelte';
|
||||
import { push } from 'svelte-spa-router';
|
||||
import SubnetOptions from '../lib/SubnetOptions.svelte';
|
||||
import QrCode from 'svelte-qrcode';
|
||||
|
||||
export let basepath = "/";
|
||||
export let sysinfo = {};
|
||||
export let data;
|
||||
let basepath = "/";
|
||||
let sysinfo = {};
|
||||
let data;
|
||||
|
||||
let form;
|
||||
sysinfoStore.subscribe(v => sysinfo = v);
|
||||
dataStore.subscribe(v => data = v);
|
||||
|
||||
let translations = {};
|
||||
translationsStore.subscribe(update => {
|
||||
translations = update;
|
||||
@@ -151,7 +153,7 @@
|
||||
});
|
||||
|
||||
saving = false;
|
||||
navigate(basepath);
|
||||
push(basepath);
|
||||
}
|
||||
|
||||
async function reboot() {
|
||||
@@ -249,34 +251,9 @@
|
||||
_global.bindToCloud = function() {
|
||||
console.log("BIND CALLED");
|
||||
}
|
||||
|
||||
async function toggleShowWifiPass() {
|
||||
const input = form.querySelector('input[name="wp"]');
|
||||
toggleShowPass.call(this, input);
|
||||
}
|
||||
|
||||
async function toggleShowMqttPass() {
|
||||
const input = form.querySelector('input[name="qa"]');
|
||||
toggleShowPass.call(this, input);
|
||||
}
|
||||
|
||||
async function toggleShowWebPass() {
|
||||
const input = form.querySelector('input[name="gp"]');
|
||||
toggleShowPass.call(this, input);
|
||||
}
|
||||
|
||||
async function toggleShowPass(input) {
|
||||
if(input.type === 'password') {
|
||||
input.type = 'text';
|
||||
this.textContent = '🙈';
|
||||
} else {
|
||||
input.type = 'password';
|
||||
this.textContent = '👁️';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<form bind:this={form} on:submit|preventDefault={handleSubmit} autocomplete="off">
|
||||
<form on:submit|preventDefault={handleSubmit} autocomplete="off">
|
||||
<div class="grid xl:grid-cols-4 lg:grid-cols-2 md:grid-cols-2">
|
||||
{#if configuration?.g}
|
||||
<div class="cnt">
|
||||
@@ -362,7 +339,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-1">
|
||||
<Link to="/priceconfig" class="text-blue-600 hover:text-blue-800">{translations.conf?.price?.conf ?? "Configure"}</Link>
|
||||
<a href="#/priceconfig" class="text-blue-600 hover:text-blue-800">{translations.conf?.price?.conf ?? "Configure"}</a>
|
||||
</div>
|
||||
<div class="my-1">
|
||||
<label><input type="checkbox" name="pe" value="true" bind:checked={configuration.p.e} class="rounded mb-1"/> {translations.conf?.price?.enabled ?? "Enabled"}</label>
|
||||
@@ -386,10 +363,7 @@
|
||||
</div>
|
||||
<div class="my-1">
|
||||
{translations.conf?.general?.security?.password ?? "Password"}<br/>
|
||||
<div class="flex">
|
||||
<input name="gp" bind:value={configuration.g.p} type="password" class="in-f w-full" maxlength="36" pattern={asciiPattern}/>
|
||||
<span on:click={toggleShowWebPass} class="in-post link">👁️</span>
|
||||
</div>
|
||||
<input name="gp" bind:value={configuration.g.p} type="password" class="in-s" maxlength="36" pattern={asciiPattern}/>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="my-1">
|
||||
@@ -541,10 +515,7 @@
|
||||
</div>
|
||||
<div class="my-1">
|
||||
{translations.conf?.connection?.psk ?? "Password"}<br/>
|
||||
<div class="flex">
|
||||
<input name="wp" bind:value={configuration.w.p} type="password" class="in-f w-full" pattern={asciiPatternExt}/>
|
||||
<span on:click={toggleShowWifiPass} class="in-post link">👁️</span>
|
||||
</div>
|
||||
<input name="wp" bind:value={configuration.w.p} type="password" class="in-s" pattern={asciiPatternExt}/>
|
||||
</div>
|
||||
<div class="my-1 flex">
|
||||
<div class="w-1/2">
|
||||
@@ -635,28 +606,28 @@
|
||||
<div class="my-1 flex">
|
||||
<span class="flex pr-2">
|
||||
{#if configuration.q.s.c}
|
||||
<span class="bd-on"><Link to="/mqtt-ca">{translations.conf?.mqtt?.ca_ok ?? "CA OK"}</Link></span>
|
||||
<span class="bd-on"><a href="#/mqtt-ca">{translations.conf?.mqtt?.ca_ok ?? "CA OK"}</a></span>
|
||||
<span class="bd-off" on:click={askDeleteCa} on:keypress={askDeleteCa}>🗑</span>
|
||||
{:else}
|
||||
<Link to="/mqtt-ca"><Badge color="blue" text={translations.conf?.mqtt?.btn_ca_upload ?? "Upload CA"} title={translations.conf?.mqtt?.title_ca ?? ""}/></Link>
|
||||
<a href="#/mqtt-ca"><Badge color="blue" text={translations.conf?.mqtt?.btn_ca_upload ?? "Upload CA"} title={translations.conf?.mqtt?.title_ca ?? ""}/></a>
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
<span class="flex pr-2">
|
||||
{#if configuration.q.s.r}
|
||||
<span class="bd-on"><Link to="/mqtt-cert">{translations.conf?.mqtt?.crt_ok ?? "Cert OK"}</Link></span>
|
||||
<span class="bd-on"><a href="#/mqtt-cert">{translations.conf?.mqtt?.crt_ok ?? "Cert OK"}</a></span>
|
||||
<span class="bd-off" on:click={askDeleteCert} on:keypress={askDeleteCert}>🗑</span>
|
||||
{:else}
|
||||
<Link to="/mqtt-cert"><Badge color="blue" text={translations.conf?.mqtt?.btn_crt_upload ?? "Upload cert"} title={translations.conf?.mqtt?.title_crt ?? ""}/></Link>
|
||||
<a href="#/mqtt-cert"><Badge color="blue" text={translations.conf?.mqtt?.btn_crt_upload ?? "Upload cert"} title={translations.conf?.mqtt?.title_crt ?? ""}/></a>
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
<span class="flex pr-2">
|
||||
{#if configuration.q.s.k}
|
||||
<span class="bd-on"><Link to="/mqtt-key">{translations.conf?.mqtt?.key_ok ?? "Key OK"}</Link></span>
|
||||
<span class="bd-on"><a href="#/mqtt-key">{translations.conf?.mqtt?.key_ok ?? "Key OK"}</a></span>
|
||||
<span class="bd-off" on:click={askDeleteKey} on:keypress={askDeleteKey}>🗑</span>
|
||||
{:else}
|
||||
<Link to="/mqtt-key"><Badge color="blue" text={translations.conf?.mqtt?.btn_key_upload ?? "Upload key"} title={translations.conf?.mqtt?.title_key ?? ""}/></Link>
|
||||
<a href="#/mqtt-key"><Badge color="blue" text={translations.conf?.mqtt?.btn_key_upload ?? "Upload key"} title={translations.conf?.mqtt?.title_key ?? ""}/></a>
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
@@ -667,10 +638,7 @@
|
||||
</div>
|
||||
<div class="my-1">
|
||||
{translations.conf?.mqtt?.pass ?? "Password"}<br/>
|
||||
<div class="flex">
|
||||
<input name="qa" bind:value={configuration.q.a} type="password" class="in-f w-full" pattern={asciiPatternExt}/>
|
||||
<span on:click={toggleShowMqttPass} class="in-post link">👁️</span>
|
||||
</div>
|
||||
<input name="qa" bind:value={configuration.q.a} type="password" class="in-s" pattern={asciiPatternExt}/>
|
||||
</div>
|
||||
<div class="my-1 flex">
|
||||
<div>
|
||||
@@ -1,18 +1,19 @@
|
||||
<script>
|
||||
import { sysinfoStore } from './DataStores.js';
|
||||
import { translationsStore } from './TranslationService.js';
|
||||
import Mask from './Mask.svelte'
|
||||
import { navigate } from 'svelte-navigator';
|
||||
import { wiki } from './Helpers';
|
||||
import { sysinfoStore } from '../lib/DataStores.js';
|
||||
import { translationsStore } from '../lib/TranslationService.js';
|
||||
import Mask from '../lib/Mask.svelte'
|
||||
import { push } from 'svelte-spa-router';
|
||||
|
||||
export let basepath = "/";
|
||||
export let sysinfo = {};
|
||||
let basepath = "/";
|
||||
let sysinfo = {};
|
||||
|
||||
let translations = {};
|
||||
translationsStore.subscribe(update => {
|
||||
translations = update;
|
||||
});
|
||||
|
||||
sysinfoStore.subscribe(v => sysinfo = v);
|
||||
|
||||
let loadingOrSaving = false;
|
||||
|
||||
async function handleSubmit(e) {
|
||||
@@ -36,7 +37,7 @@
|
||||
s.booting = res.reboot;
|
||||
return s;
|
||||
});
|
||||
navigate(basepath);
|
||||
push(basepath);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,26 +1,38 @@
|
||||
<script>
|
||||
import { ampcol, exportcol, metertype, uiVisibility, formatUnit, fmtnum, formatCurrency } from './Helpers.js';
|
||||
import PowerGauge from './PowerGauge.svelte';
|
||||
import VoltPlot from './VoltPlot.svelte';
|
||||
import ReactiveData from './ReactiveData.svelte';
|
||||
import AccountingData from './AccountingData.svelte';
|
||||
import PricePlot from './PricePlot.svelte';
|
||||
import DayPlot from './DayPlot.svelte';
|
||||
import MonthPlot from './MonthPlot.svelte';
|
||||
import TemperaturePlot from './TemperaturePlot.svelte';
|
||||
import TariffPeakChart from './TariffPeakChart.svelte';
|
||||
import RealtimePlot from './RealtimePlot.svelte';
|
||||
import PerPhasePlot from './PerPhasePlot.svelte';
|
||||
import { ampcol, exportcol, metertype, uiVisibility, formatUnit, fmtnum, formatCurrency } from '../lib/Helpers.js';
|
||||
import PowerGauge from '../lib/PowerGauge.svelte';
|
||||
import VoltPlot from '../lib/VoltPlot.svelte';
|
||||
import ReactiveData from '../lib/ReactiveData.svelte';
|
||||
import AccountingData from '../lib/AccountingData.svelte';
|
||||
import PricePlot from '../lib/PricePlot.svelte';
|
||||
import DayPlot from '../lib/DayPlot.svelte';
|
||||
import MonthPlot from '../lib/MonthPlot.svelte';
|
||||
import TemperaturePlot from '../lib/TemperaturePlot.svelte';
|
||||
import TariffPeakChart from '../lib/TariffPeakChart.svelte';
|
||||
import RealtimePlot from '../lib/RealtimePlot.svelte';
|
||||
import PerPhasePlot from '../lib/PerPhasePlot.svelte';
|
||||
import { dataStore, sysinfoStore, importPricesStore, exportPricesStore, dayPlotStore, monthPlotStore, temperaturesStore, tariffStore } from '../lib/DataStores.js';
|
||||
import { translationsStore } from '../lib/TranslationService.js';
|
||||
|
||||
export let data = {}
|
||||
export let sysinfo = {}
|
||||
export let importPrices = {}
|
||||
export let exportPrices = {}
|
||||
export let dayPlot = {}
|
||||
export let monthPlot = {}
|
||||
export let temperatures = {};
|
||||
export let translations = {};
|
||||
export let tariffData = {};
|
||||
let data = {}
|
||||
let sysinfo = {}
|
||||
let importPrices = {}
|
||||
let exportPrices = {}
|
||||
let dayPlot = {}
|
||||
let monthPlot = {}
|
||||
let temperatures = {};
|
||||
let translations = {};
|
||||
let tariffData = {};
|
||||
|
||||
dataStore.subscribe(v => data = v);
|
||||
sysinfoStore.subscribe(v => sysinfo = v);
|
||||
importPricesStore.subscribe(v => importPrices = v);
|
||||
exportPricesStore.subscribe(v => exportPrices = v);
|
||||
dayPlotStore.subscribe(v => dayPlot = v);
|
||||
monthPlotStore.subscribe(v => monthPlot = v);
|
||||
temperaturesStore.subscribe(v => temperatures = v);
|
||||
translationsStore.subscribe(v => translations = v);
|
||||
tariffStore.subscribe(v => tariffData = v);
|
||||
|
||||
let it,et,threePhase, l1e, l2e, l3e;
|
||||
$: {
|
||||
11
lib/SvelteUi/app/src/routes/EditDayRoute.svelte
Normal file
11
lib/SvelteUi/app/src/routes/EditDayRoute.svelte
Normal file
@@ -0,0 +1,11 @@
|
||||
<script>
|
||||
import DataEdit from '../lib/DataEdit.svelte';
|
||||
import { dayPlotStore } from '../lib/DataStores.js';
|
||||
|
||||
let basepath = "/";
|
||||
let dayPlot;
|
||||
|
||||
dayPlotStore.subscribe(v => dayPlot = v);
|
||||
</script>
|
||||
|
||||
<DataEdit prefix="UTC Hour" data={dayPlot} url="/dayplot" {basepath} />
|
||||
11
lib/SvelteUi/app/src/routes/EditMonthRoute.svelte
Normal file
11
lib/SvelteUi/app/src/routes/EditMonthRoute.svelte
Normal file
@@ -0,0 +1,11 @@
|
||||
<script>
|
||||
import DataEdit from '../lib/DataEdit.svelte';
|
||||
import { monthPlotStore } from '../lib/DataStores.js';
|
||||
|
||||
let basepath = "/";
|
||||
let monthPlot;
|
||||
|
||||
monthPlotStore.subscribe(v => monthPlot = v);
|
||||
</script>
|
||||
|
||||
<DataEdit prefix="Day" data={monthPlot} url="/monthplot" {basepath} />
|
||||
@@ -1,9 +1,6 @@
|
||||
<script>
|
||||
import Mask from "./Mask.svelte";
|
||||
import { translationsStore } from "./TranslationService";
|
||||
|
||||
export let action;
|
||||
export let title;
|
||||
import Mask from "../lib/Mask.svelte";
|
||||
import { translationsStore } from "../lib/TranslationService";
|
||||
|
||||
let translations = {};
|
||||
translationsStore.subscribe(update => {
|
||||
@@ -15,12 +12,12 @@
|
||||
|
||||
<div class="grid xl:grid-cols-4 lg:grid-cols-2 md:grid-cols-2">
|
||||
<div class="cnt">
|
||||
<strong>{translations.upload?.title ?? "Upload"} {title}</strong>
|
||||
<strong>{translations.upload?.title ?? "Upload"} CA</strong>
|
||||
<p class="mb-4">{translations.upload?.desc ?? ""}</p>
|
||||
<form action="{action}" enctype="multipart/form-data" method="post" on:submit={() => uploading=true} autocomplete="off">
|
||||
<form action="/mqtt-ca" enctype="multipart/form-data" method="post" on:submit={() => uploading=true} autocomplete="off">
|
||||
<input name="file" type="file">
|
||||
<div class="w-full text-right mt-4">
|
||||
<button type="submit" class="btn-pri"><p class="mb-4">{translations.btn?.upload ?? "Upload"}</button>
|
||||
<button type="submit" class="btn-pri">{translations.btn?.upload ?? "Upload"}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
25
lib/SvelteUi/app/src/routes/MqttCertRoute.svelte
Normal file
25
lib/SvelteUi/app/src/routes/MqttCertRoute.svelte
Normal file
@@ -0,0 +1,25 @@
|
||||
<script>
|
||||
import Mask from "../lib/Mask.svelte";
|
||||
import { translationsStore } from "../lib/TranslationService";
|
||||
|
||||
let translations = {};
|
||||
translationsStore.subscribe(update => {
|
||||
translations = update;
|
||||
});
|
||||
|
||||
let uploading = false;
|
||||
</script>
|
||||
|
||||
<div class="grid xl:grid-cols-4 lg:grid-cols-2 md:grid-cols-2">
|
||||
<div class="cnt">
|
||||
<strong>{translations.upload?.title ?? "Upload"} certificate</strong>
|
||||
<p class="mb-4">{translations.upload?.desc ?? ""}</p>
|
||||
<form action="/mqtt-cert" enctype="multipart/form-data" method="post" on:submit={() => uploading=true} autocomplete="off">
|
||||
<input name="file" type="file">
|
||||
<div class="w-full text-right mt-4">
|
||||
<button type="submit" class="btn-pri">{translations.btn?.upload ?? "Upload"}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<Mask active={uploading} message={translations.upload?.mask ?? "Uploading"}/>
|
||||
25
lib/SvelteUi/app/src/routes/MqttKeyRoute.svelte
Normal file
25
lib/SvelteUi/app/src/routes/MqttKeyRoute.svelte
Normal file
@@ -0,0 +1,25 @@
|
||||
<script>
|
||||
import Mask from "../lib/Mask.svelte";
|
||||
import { translationsStore } from "../lib/TranslationService";
|
||||
|
||||
let translations = {};
|
||||
translationsStore.subscribe(update => {
|
||||
translations = update;
|
||||
});
|
||||
|
||||
let uploading = false;
|
||||
</script>
|
||||
|
||||
<div class="grid xl:grid-cols-4 lg:grid-cols-2 md:grid-cols-2">
|
||||
<div class="cnt">
|
||||
<strong>{translations.upload?.title ?? "Upload"} private key</strong>
|
||||
<p class="mb-4">{translations.upload?.desc ?? ""}</p>
|
||||
<form action="/mqtt-key" enctype="multipart/form-data" method="post" on:submit={() => uploading=true} autocomplete="off">
|
||||
<input name="file" type="file">
|
||||
<div class="w-full text-right mt-4">
|
||||
<button type="submit" class="btn-pri">{translations.btn?.upload ?? "Upload"}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<Mask active={uploading} message={translations.upload?.mask ?? "Uploading"}/>
|
||||
@@ -1,11 +1,9 @@
|
||||
<script>
|
||||
import { priceConfigStore, getPriceConfig } from './ConfigurationStore'
|
||||
import { translationsStore } from './TranslationService';
|
||||
import { wiki, zeropad } from './Helpers.js';
|
||||
import Mask from './Mask.svelte'
|
||||
import { navigate } from 'svelte-navigator';
|
||||
|
||||
export let basepath = "/";
|
||||
import { priceConfigStore, getPriceConfig } from '../lib/ConfigurationStore'
|
||||
import { translationsStore } from '../lib/TranslationService';
|
||||
import { wiki, zeropad } from '../lib/Helpers.js';
|
||||
import Mask from '../lib/Mask.svelte'
|
||||
import { push } from 'svelte-spa-router';
|
||||
|
||||
let translations = {};
|
||||
translationsStore.subscribe(update => {
|
||||
@@ -53,7 +51,7 @@
|
||||
let res = (await response.json())
|
||||
|
||||
saving = false;
|
||||
navigate(basepath + "configuration");
|
||||
push("/configuration");
|
||||
}
|
||||
|
||||
let toggleDay = function(arr, day) {
|
||||
@@ -1,34 +1,27 @@
|
||||
<script>
|
||||
import { sysinfoStore, networksStore } from './DataStores.js';
|
||||
import { translationsStore } from './TranslationService.js';
|
||||
import Mask from './Mask.svelte'
|
||||
import SubnetOptions from './SubnetOptions.svelte';
|
||||
import { scanForDevice, charAndNumPattern, asciiPatternExt, ipPattern } from './Helpers.js';
|
||||
import { sysinfoStore, networksStore } from '../lib/DataStores.js';
|
||||
import { translationsStore } from '../lib/TranslationService.js';
|
||||
import Mask from '../lib/Mask.svelte'
|
||||
import SubnetOptions from '../lib/SubnetOptions.svelte';
|
||||
import { scanForDevice, charAndNumPattern, asciiPatternExt, ipPattern } from '../lib/Helpers.js';
|
||||
|
||||
let translations = {};
|
||||
translationsStore.subscribe(update => {
|
||||
translations = update;
|
||||
});
|
||||
|
||||
let form;
|
||||
let ssid = '';
|
||||
let psk = '';
|
||||
let manual = false;
|
||||
let networks = {};
|
||||
networksStore.subscribe(update => {
|
||||
networks = update;
|
||||
manual = update?.c == 0;
|
||||
ssid = update?.n[0]?.s ?? '';
|
||||
});
|
||||
|
||||
export let sysinfo = {}
|
||||
let sysinfo = {}
|
||||
sysinfoStore.subscribe(v => sysinfo = v);
|
||||
|
||||
let staticIp = false;
|
||||
let connectionMode = 1;
|
||||
let loadingOrSaving = false;
|
||||
let wifiTestInProgress = false;
|
||||
let wifiTestOk = false;
|
||||
let wifiTestError = 0;
|
||||
|
||||
function updateSysinfo(url) {
|
||||
sysinfoStore.update(s => {
|
||||
@@ -37,9 +30,9 @@
|
||||
});
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
async function handleSubmit(e) {
|
||||
loadingOrSaving = true;
|
||||
const formData = new FormData(form);
|
||||
const formData = new FormData(e.target);
|
||||
const data = new URLSearchParams();
|
||||
for (let field of formData) {
|
||||
const [key, value] = field;
|
||||
@@ -67,71 +60,17 @@
|
||||
return s;
|
||||
});
|
||||
}
|
||||
|
||||
async function wifiTest() {
|
||||
let response;
|
||||
if(wifiTestInProgress) {
|
||||
response = await fetch('wifitest.json');
|
||||
} else {
|
||||
wifiTestInProgress = true;
|
||||
wifiTestOk = false;
|
||||
const data = new URLSearchParams();
|
||||
data.append('ssid', ssid);
|
||||
data.append('psk', psk);
|
||||
response = await fetch('wifitest.json', {
|
||||
method: 'POST',
|
||||
body: data
|
||||
});
|
||||
}
|
||||
const res = await response.json();
|
||||
if(res?.time == 0) {
|
||||
wifiTestInProgress = false;
|
||||
wifiTestOk = res.status == 3;
|
||||
wifiTestError = res.status;
|
||||
if(wifiTestOk) {
|
||||
sysinfoStore.update(s => {
|
||||
s.net.ip = res.ip;
|
||||
return s;
|
||||
});
|
||||
setTimeout(handleSubmit, 1000);
|
||||
}
|
||||
} else if(wifiTestInProgress) {
|
||||
if(res.time > 30000) {
|
||||
wifiTestError = 4;
|
||||
wifiTestInProgress = false;
|
||||
} else {
|
||||
setTimeout(wifiTest, 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function resetWifiTest() {
|
||||
wifiTestInProgress = false;
|
||||
wifiTestOk = false;
|
||||
wifiTestError = 0;
|
||||
}
|
||||
|
||||
async function toggleShowPass() {
|
||||
const input = form.querySelector('input[name="sp"]');
|
||||
if(input.type === 'password') {
|
||||
input.type = 'text';
|
||||
this.textContent = '🙈';
|
||||
} else {
|
||||
input.type = 'password';
|
||||
this.textContent = '👁️';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<div class="grid xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2">
|
||||
<div class="cnt">
|
||||
<form bind:this={form} on:submit|preventDefault={handleSubmit}>
|
||||
<form on:submit|preventDefault={handleSubmit}>
|
||||
<input type="hidden" name="s" value="true"/>
|
||||
<strong class="text-sm">{translations.setup?.title ?? "Setup"}</strong>
|
||||
<div class="my-3">
|
||||
{translations.conf?.connection?.title ?? "Connection"}<br/>
|
||||
<select name="sc" class="in-s" bind:value={connectionMode} on:input={resetWifiTest}>
|
||||
<select name="sc" class="in-s" bind:value={connectionMode}>
|
||||
<option value={1}>{translations.conf?.connection?.wifi ?? "Connect to WiFi"}</option>
|
||||
<option value={2}>{translations.conf?.connection?.ap ?? "Standalone access point"}</option>
|
||||
{#if sysinfo.if && sysinfo.if.eth}
|
||||
@@ -145,9 +84,9 @@
|
||||
<label class="float-right mr-3"><input type="checkbox" value="true" bind:checked={manual} class="rounded mb-1"/> manual</label>
|
||||
<br/>
|
||||
{#if manual}
|
||||
<input name="ss" bind:value={ssid} on:input={resetWifiTest} type="text" pattern={asciiPatternExt} class="in-s" required={connectionMode == 1 || connectionMode == 2}/>
|
||||
<input name="ss" type="text" pattern={asciiPatternExt} class="in-s" required={connectionMode == 1 || connectionMode == 2}/>
|
||||
{:else}
|
||||
<select name="ss" bind:value={ssid} on:change={resetWifiTest} class="in-s" required={connectionMode == 1 || connectionMode == 2}>
|
||||
<select name="ss" class="in-s" required={connectionMode == 1 || connectionMode == 2}>
|
||||
{#if networks?.c == -1}
|
||||
<option value="" selected disabled>Scanning...</option>
|
||||
{/if}
|
||||
@@ -161,10 +100,7 @@
|
||||
</div>
|
||||
<div class="my-3">
|
||||
{translations.conf?.connection?.psk ?? "Password"}<br/>
|
||||
<div class="flex">
|
||||
<input name="sp" bind:value={psk} on:input={resetWifiTest} type="password" pattern={asciiPatternExt} class="in-f w-full" autocomplete="off" required={connectionMode == 2}/>
|
||||
<span on:click={toggleShowPass} class="in-post link">👁️</span>
|
||||
</div>
|
||||
<input name="sp" type="password" pattern={asciiPatternExt} class="in-s" autocomplete="off" required={connectionMode == 2}/>
|
||||
</div>
|
||||
{/if}
|
||||
<div>
|
||||
@@ -196,21 +132,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
<div class="my-3">
|
||||
{#if connectionMode != 1}
|
||||
<button type="submit" class="btn-pri">{translations.btn?.save ?? "Save"}</button>
|
||||
{:else if wifiTestOk}
|
||||
<div class="bd-green">{translations.setup?.testok ?? "Connection successful (" + sysinfo.net.ip + ")"}</div>
|
||||
<button type="submit" class="btn-pri">{translations.btn?.save ?? "Save"}</button>
|
||||
{:else if wifiTestInProgress}
|
||||
<div class="bd-yellow">{translations.setup?.testconn ?? "Testing connection"}</div>
|
||||
{:else}
|
||||
{#if wifiTestError}
|
||||
<div class="bd-red">{ (translations.setup?.testfail ?? "Connection failed") + ': ' + (translations.errors?.wifi?.[wifiTestError] ?? wifiTestError) }</div>
|
||||
<button type="submit" class="btn-pri">{translations.btn?.forcesave ?? "Force save"}</button>
|
||||
{:else}
|
||||
<button type="button" class="btn-pri" on:click={wifiTest}>{translations.btn?.save ?? "Save"}</button>
|
||||
{/if}
|
||||
{/if}
|
||||
<button type="submit" class="btn-pri">{translations.btn?.save ?? "Save"}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -1,16 +1,70 @@
|
||||
<script>
|
||||
import { metertype, boardtype, isBusPowered, getBaseChip, wiki } from './Helpers.js';
|
||||
import { getSysinfo, sysinfoStore } from './DataStores.js';
|
||||
import { upgrade, upgradeWarningText } from './UpgradeHelper';
|
||||
import { translationsStore } from './TranslationService.js';
|
||||
import { Link } from 'svelte-navigator';
|
||||
import Clock from './Clock.svelte';
|
||||
import Mask from './Mask.svelte';
|
||||
import { scanForDevice } from './Helpers.js';
|
||||
import ipaddr from 'ipaddr.js';
|
||||
import { metertype, boardtype, isBusPowered, getBaseChip, wiki } from '../lib/Helpers.js';
|
||||
import { getSysinfo, sysinfoStore, dataStore } from '../lib/DataStores.js';
|
||||
import { upgrade, upgradeWarningText } from '../lib/UpgradeHelper';
|
||||
import { translationsStore } from '../lib/TranslationService.js';
|
||||
import Clock from '../lib/Clock.svelte';
|
||||
import Mask from '../lib/Mask.svelte';
|
||||
import { scanForDevice } from '../lib/Helpers.js';
|
||||
|
||||
export let data;
|
||||
export let sysinfo;
|
||||
let data;
|
||||
let sysinfo;
|
||||
|
||||
dataStore.subscribe(v => data = v);
|
||||
sysinfoStore.subscribe(v => sysinfo = v);
|
||||
|
||||
// Format IPv6 address to compact form (RFC 5952)
|
||||
const formatIPv6 = (addr) => {
|
||||
if (!addr) return addr;
|
||||
|
||||
// Split into groups
|
||||
const groups = addr.toLowerCase().split(':');
|
||||
|
||||
// Remove leading zeros from each group
|
||||
const normalized = groups.map(g => g.replace(/^0+/, '') || '0');
|
||||
|
||||
// Find longest sequence of consecutive zeros
|
||||
let maxStart = -1, maxLen = 0;
|
||||
let currStart = -1, currLen = 0;
|
||||
|
||||
for (let i = 0; i < normalized.length; i++) {
|
||||
if (normalized[i] === '0') {
|
||||
if (currStart === -1) currStart = i;
|
||||
currLen++;
|
||||
} else {
|
||||
if (currLen > maxLen) {
|
||||
maxStart = currStart;
|
||||
maxLen = currLen;
|
||||
}
|
||||
currStart = -1;
|
||||
currLen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Check final sequence
|
||||
if (currLen > maxLen) {
|
||||
maxStart = currStart;
|
||||
maxLen = currLen;
|
||||
}
|
||||
|
||||
// Only compress if we have 2 or more consecutive zeros
|
||||
if (maxLen > 1) {
|
||||
const before = normalized.slice(0, maxStart);
|
||||
const after = normalized.slice(maxStart + maxLen);
|
||||
|
||||
if (before.length === 0 && after.length === 0) {
|
||||
return '::';
|
||||
} else if (before.length === 0) {
|
||||
return '::' + after.join(':');
|
||||
} else if (after.length === 0) {
|
||||
return before.join(':') + '::';
|
||||
} else {
|
||||
return before.join(':') + '::' + after.join(':');
|
||||
}
|
||||
}
|
||||
|
||||
return normalized.join(':');
|
||||
};
|
||||
|
||||
let cfgItems = [{
|
||||
name: 'WiFi',
|
||||
@@ -73,11 +127,11 @@
|
||||
}
|
||||
|
||||
let firmwareFileInput;
|
||||
let firmwareFiles = [];
|
||||
let firmwareFiles = null;
|
||||
let firmwareUploading = false;
|
||||
|
||||
let configFileInput;
|
||||
let configFiles = [];
|
||||
let configFiles = null;
|
||||
let configUploading = false;
|
||||
|
||||
getSysinfo();
|
||||
@@ -119,7 +173,7 @@
|
||||
};
|
||||
|
||||
$: {
|
||||
if(configFiles.length == 1) {
|
||||
if(configFiles && configFiles.length == 1) {
|
||||
let file = configFiles[0];
|
||||
let reader = new FileReader();
|
||||
let parseConfigFile = ( e ) => {
|
||||
@@ -146,7 +200,7 @@
|
||||
{translations.status?.device?.chip ?? "Chip"}: {sysinfo.chip} {#if sysinfo.cpu}({sysinfo.cpu}MHz){/if}
|
||||
</div>
|
||||
<div class="my-2">
|
||||
{translations.status?.device?.device ?? "Device"}: <Link to="/vendor">{boardtype(sysinfo.chip, sysinfo.board)}</Link>
|
||||
{translations.status?.device?.device ?? "Device"}: <a href="#/vendor">{boardtype(sysinfo.chip, sysinfo.board)}</a>
|
||||
</div>
|
||||
<div class="my-2">
|
||||
{translations.status?.device?.mac ?? "MAC"}: {sysinfo.mac}
|
||||
@@ -169,9 +223,9 @@
|
||||
{/if}
|
||||
{#if data?.a}
|
||||
<div class="my-2">
|
||||
<Link to="/consent">
|
||||
<a href="#/consent">
|
||||
<span class="btn-pri-sm">{translations.status?.device?.btn_consents ?? "Consents"}</span>
|
||||
</Link>
|
||||
</a>
|
||||
<button on:click={askReboot} class="btn-yellow-sm float-right">{translations.btn?.reboot ?? "Reboot"}</button>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -208,11 +262,11 @@
|
||||
</div>
|
||||
{#if sysinfo.net.ipv6}
|
||||
<div class="my-2">
|
||||
IPv6: <span style="font-size: 14px;">{ipaddr.parse(sysinfo.net.ipv6)}</span>
|
||||
IPv6: <span style="font-size: 14px;">{formatIPv6(sysinfo.net.ipv6)}</span>
|
||||
</div>
|
||||
<div class="my-2">
|
||||
{#if sysinfo.net.dns1v6}DNSv6: <span style="font-size: 14px;">{ipaddr.parse(sysinfo.net.dns1v6)}</span>{/if}
|
||||
{#if sysinfo.net.dns2v6}DNSv6: <span style="font-size: 14px;">{ipaddr.parse(sysinfo.net.dns2v6)}</span>{/if}
|
||||
{#if sysinfo.net.dns1v6}DNSv6: <span style="font-size: 14px;">{formatIPv6(sysinfo.net.dns1v6)}</span>{/if}
|
||||
{#if sysinfo.net.dns2v6}DNSv6: <span style="font-size: 14px;">{formatIPv6(sysinfo.net.dns2v6)}</span>{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -267,7 +321,7 @@
|
||||
<div class="my-2 flex">
|
||||
<form action="firmware" enctype="multipart/form-data" method="post" on:submit={() => firmwareUploading=true} autocomplete="off">
|
||||
<input style="display:none" name="file" type="file" accept=".bin" bind:this={firmwareFileInput} bind:files={firmwareFiles}>
|
||||
{#if firmwareFiles.length == 0}
|
||||
{#if !firmwareFiles || firmwareFiles.length == 0}
|
||||
<button type="button" on:click={()=>{firmwareFileInput.click();}} class="btn-pri-sm float-right">{translations.status?.firmware?.btn_select_file ?? "Select file"}</button>
|
||||
{:else}
|
||||
{firmwareFiles[0].name}
|
||||
@@ -287,13 +341,13 @@
|
||||
{/each}
|
||||
<label class="my-1 mx-3 col-span-2"><input type="checkbox" class="rounded" name="ic" value="true"/> {translations.status?.backup?.secrets ?? "Include secrets"}<br/><small>{translations.status?.backup?.secrets_desc ?? ""}</small></label>
|
||||
</div>
|
||||
{#if configFiles.length == 0}
|
||||
{#if !configFiles || configFiles.length == 0}
|
||||
<button type="submit" class="btn-pri-sm float-right">{translations.status?.backup?.btn_download ?? "Download"}</button>
|
||||
{/if}
|
||||
</form>
|
||||
<form on:submit|preventDefault={uploadConfigFile} autocomplete="off">
|
||||
<input style="display:none" name="file" type="file" accept=".cfg" bind:this={configFileInput} bind:files={configFiles}>
|
||||
{#if configFiles.length == 0}
|
||||
{#if !configFiles || configFiles.length == 0}
|
||||
<button type="button" on:click={()=>{configFileInput.click();}} class="btn-pri-sm">{translations.status?.backup?.btn_select_file ?? "Select file"}</button>
|
||||
{:else}
|
||||
{configFiles[0].name}
|
||||
@@ -1,12 +1,11 @@
|
||||
<script>
|
||||
import { sysinfoStore } from './DataStores.js';
|
||||
import BoardTypeSelectOptions from './BoardTypeSelectOptions.svelte';
|
||||
import UartSelectOptions from './UartSelectOptions.svelte';
|
||||
import Mask from './Mask.svelte'
|
||||
import { navigate } from 'svelte-navigator';
|
||||
import { sysinfoStore } from '../lib/DataStores.js';
|
||||
import BoardTypeSelectOptions from '../lib/BoardTypeSelectOptions.svelte';
|
||||
import UartSelectOptions from '../lib/UartSelectOptions.svelte';
|
||||
import Mask from '../lib/Mask.svelte'
|
||||
import { push } from 'svelte-spa-router';
|
||||
|
||||
export let basepath = "/";
|
||||
export let sysinfo = {};
|
||||
let sysinfo = {};
|
||||
|
||||
let loadingOrSaving = false;
|
||||
async function handleSubmit(e) {
|
||||
@@ -32,7 +31,7 @@
|
||||
|
||||
return s;
|
||||
});
|
||||
navigate(basepath + (sysinfo.usrcfg ? "" : "setup"));
|
||||
push(sysinfo.usrcfg ? "/" : "/setup");
|
||||
}
|
||||
|
||||
let cc = true;
|
||||
@@ -1,46 +1,62 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import { svelte } from '@sveltejs/vite-plugin-svelte'
|
||||
|
||||
// Try to import local config, fall back to default if not found
|
||||
let localConfig = { proxyTarget: "http://192.168.4.1" };
|
||||
try {
|
||||
const imported = await import('./vite.config.local.js');
|
||||
localConfig = imported.default;
|
||||
} catch (e) {
|
||||
console.log('No vite.config.local.js found, using default proxy target:', localConfig.proxyTarget);
|
||||
console.log('Copy vite.config.local.example.js to vite.config.local.js to customize');
|
||||
}
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
assetsDir: '.',
|
||||
minify: 'esbuild',
|
||||
target: 'es2020',
|
||||
rollupOptions: {
|
||||
output: {
|
||||
assetFileNames: '[name][extname]',
|
||||
chunkFileNames: '[name].js',
|
||||
entryFileNames: '[name].js'
|
||||
entryFileNames: '[name].js',
|
||||
manualChunks: undefined
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [svelte()],
|
||||
plugins: [svelte({
|
||||
compilerOptions: {
|
||||
dev: false
|
||||
}
|
||||
})],
|
||||
server: {
|
||||
proxy: {
|
||||
"/data.json": "http://192.168.4.1",
|
||||
"/energyprice.json": "http://192.168.4.1",
|
||||
"/importprice.json": "http://192.168.4.1",
|
||||
"/exportprice.json": "http://192.168.4.1",
|
||||
"/dayplot.json": "http://192.168.4.1",
|
||||
"/monthplot.json": "http://192.168.4.1",
|
||||
"/temperature.json": "http://192.168.4.1",
|
||||
"/sysinfo.json": "http://192.168.4.1",
|
||||
"/configuration.json": "http://192.168.4.1",
|
||||
"/tariff.json": "http://192.168.4.1",
|
||||
"/realtime.json": "http://192.168.4.1",
|
||||
"/priceconfig.json": "http://192.168.4.1",
|
||||
"/translations.json": "http://192.168.4.1",
|
||||
"/cloudkey.json": "http://192.168.4.1",
|
||||
"/wifiscan.json": "http://192.168.4.1",
|
||||
"/wifitest.json": "http://192.168.4.1",
|
||||
"/save": "http://192.168.4.1",
|
||||
"/reboot": "http://192.168.4.1",
|
||||
"/configfile": "http://192.168.4.1",
|
||||
"/upgrade": "http://192.168.4.1",
|
||||
"/mqtt-ca": "http://192.168.4.1",
|
||||
"/mqtt-cert": "http://192.168.4.1",
|
||||
"/mqtt-key": "http://192.168.4.1",
|
||||
"/logo.svg": "http://192.168.4.1",
|
||||
"/data.json": localConfig.proxyTarget,
|
||||
"/energyprice.json": localConfig.proxyTarget,
|
||||
"/importprice.json": localConfig.proxyTarget,
|
||||
"/exportprice.json": localConfig.proxyTarget,
|
||||
"/dayplot.json": localConfig.proxyTarget,
|
||||
"/monthplot.json": localConfig.proxyTarget,
|
||||
"/temperature.json": localConfig.proxyTarget,
|
||||
"/sysinfo.json": localConfig.proxyTarget,
|
||||
"/configuration.json": localConfig.proxyTarget,
|
||||
"/tariff.json": localConfig.proxyTarget,
|
||||
"/realtime.json": localConfig.proxyTarget,
|
||||
"/priceconfig.json": localConfig.proxyTarget,
|
||||
"/translations.json": localConfig.proxyTarget,
|
||||
"/cloudkey.json": localConfig.proxyTarget,
|
||||
"/wifiscan.json": localConfig.proxyTarget,
|
||||
"/save": localConfig.proxyTarget,
|
||||
"/reboot": localConfig.proxyTarget,
|
||||
"/configfile": localConfig.proxyTarget,
|
||||
"/upgrade": localConfig.proxyTarget,
|
||||
"/mqtt-ca": localConfig.proxyTarget,
|
||||
"/mqtt-cert": localConfig.proxyTarget,
|
||||
"/mqtt-key": localConfig.proxyTarget,
|
||||
"/logo.svg": localConfig.proxyTarget,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
7
lib/SvelteUi/app/vite.config.local.example.js
Normal file
7
lib/SvelteUi/app/vite.config.local.example.js
Normal file
@@ -0,0 +1,7 @@
|
||||
// Copy this file to vite.config.local.js and update with your device's IP address
|
||||
// vite.config.local.js is ignored by git so your settings won't be committed
|
||||
|
||||
export default {
|
||||
// The IP address of your AMS reader device for local development
|
||||
proxyTarget: "http://192.168.4.1"
|
||||
}
|
||||
@@ -45,8 +45,6 @@
|
||||
|
||||
#include "LittleFS.h"
|
||||
|
||||
#define WIFI_TEST_TIMEOUT 30000
|
||||
|
||||
class AmsWebServer {
|
||||
public:
|
||||
#if defined(AMS_REMOTE_DEBUG)
|
||||
@@ -115,10 +113,6 @@ private:
|
||||
WebServer server;
|
||||
#endif
|
||||
|
||||
bool wifiTestInProgress = false;
|
||||
unsigned long wifiTestStarted = 0;
|
||||
uint8_t wifiTestStatusCode = 0;
|
||||
|
||||
bool checkSecurity(byte level, bool send401 = true);
|
||||
|
||||
void indexHtml();
|
||||
@@ -143,8 +137,6 @@ private:
|
||||
void cloudkeyJson();
|
||||
|
||||
void wifiScan();
|
||||
void wifiTestStart();
|
||||
void wifiTestStatus();
|
||||
|
||||
void configurationJson();
|
||||
void handleSave();
|
||||
|
||||
@@ -137,8 +137,6 @@ void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, AmsDa
|
||||
server.on(context + F("/cloudkey.json"), HTTP_GET, std::bind(&AmsWebServer::cloudkeyJson, this));
|
||||
|
||||
server.on(context + F("/wifiscan.json"), HTTP_GET, std::bind(&AmsWebServer::wifiScan, this));
|
||||
server.on(context + F("/wifitest.json"), HTTP_POST, std::bind(&AmsWebServer::wifiTestStart, this));
|
||||
server.on(context + F("/wifitest.json"), HTTP_GET, std::bind(&AmsWebServer::wifiTestStatus, this));
|
||||
|
||||
server.on(context + F("/configuration.json"), HTTP_GET, std::bind(&AmsWebServer::configurationJson, this));
|
||||
server.on(context + F("/save"), HTTP_POST, std::bind(&AmsWebServer::handleSave, this));
|
||||
@@ -2930,47 +2928,4 @@ void AmsWebServer::wifiScan() {
|
||||
|
||||
server.setContentLength(strlen(buf));
|
||||
server.send(200, MIME_JSON, buf);
|
||||
}
|
||||
|
||||
void AmsWebServer::wifiTestStart() {
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
|
||||
if(WiFi.getMode() == WIFI_AP_STA) {
|
||||
wifiTestStarted = millis();
|
||||
String ssid = server.arg(F("ssid"));
|
||||
String psk = server.arg(F("psk"));
|
||||
WiFi.begin(ssid, psk);
|
||||
wifiTestInProgress = true;
|
||||
wifiTestStatusCode = 0;
|
||||
}
|
||||
wifiTestStatus();
|
||||
}
|
||||
|
||||
void AmsWebServer::wifiTestStatus() {
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
|
||||
if(wifiTestInProgress) {
|
||||
wifiTestStatusCode = WiFi.status();
|
||||
if(wifiTestStatusCode == WL_DISCONNECTED) { // Still trying to connect
|
||||
if(millis() - wifiTestStarted > WIFI_TEST_TIMEOUT) {
|
||||
wifiTestInProgress = false;
|
||||
wifiTestStatusCode = 99; // Custom code for timeout
|
||||
}
|
||||
} else {
|
||||
wifiTestInProgress = false;
|
||||
}
|
||||
}
|
||||
|
||||
wifi_config_t conf;
|
||||
esp_wifi_get_config((wifi_interface_t)ESP_IF_WIFI_STA, &conf);
|
||||
|
||||
snprintf_P(buf, BufferSize, PSTR("{\"ssid\":\"%s\",\"status\":%d,\"time\":%lu,\"ip\":\"%s\"}"), conf.sta.ssid, wifiTestStatusCode, wifiTestInProgress ? millis() - wifiTestStarted : 0, WiFi.localIP().toString().c_str());
|
||||
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
|
||||
server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);
|
||||
server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF);
|
||||
|
||||
server.setContentLength(strlen(buf));
|
||||
server.send(200, MIME_JSON, buf);
|
||||
}
|
||||
}
|
||||
@@ -301,7 +301,18 @@ void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
}
|
||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: {
|
||||
debugW_P(PSTR("Disconnected from network"));
|
||||
if(WiFi.getMode() == WIFI_STA) {
|
||||
wifi_err_reason_t reason = (wifi_err_reason_t) info.wifi_sta_disconnected.reason;
|
||||
switch(reason) {
|
||||
case WIFI_REASON_AUTH_FAIL:
|
||||
case WIFI_REASON_NO_AP_FOUND:
|
||||
if(sysConfig.dataCollectionConsent == 0) {
|
||||
debugI_P(PSTR("Unable to connect to configured AP, swapping to AP mode"));
|
||||
toggleSetupMode();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ARDUINO_EVENT_SC_FOUND_CHANNEL:
|
||||
@@ -310,9 +321,6 @@ void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
case ARDUINO_EVENT_SC_GOT_SSID_PSWD:
|
||||
debugI_P(PSTR("SmartConfig got config"));
|
||||
break;
|
||||
default:
|
||||
debugD_P(PSTR("WiFi event: %s"), WiFi.eventName(event));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,6 +530,9 @@ void setup() {
|
||||
WiFi.disconnect(true);
|
||||
WiFi.softAPdisconnect(true);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
#if defined(ESP32)
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
#endif
|
||||
|
||||
UpgradeInformation upinfo;
|
||||
if(config.getUpgradeInformation(upinfo)) {
|
||||
@@ -1207,7 +1218,7 @@ void handleSystem(unsigned long now) {
|
||||
unsigned long start, end;
|
||||
if(now - lastSysupdate > 60000) {
|
||||
start = millis();
|
||||
if(WiFi.getMode() == WIFI_STA && WiFi.status() == WL_CONNECTED) {
|
||||
if(WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED) {
|
||||
if(mqttHandler != NULL) {
|
||||
mqttHandler->publishSystem(&hw, ps, &ea);
|
||||
mqttHandler->publishFirmware();
|
||||
@@ -1243,7 +1254,7 @@ void handleTemperature(unsigned long now) {
|
||||
if(hw.updateTemperatures()) {
|
||||
lastTemperatureRead = now;
|
||||
|
||||
if(mqttHandler != NULL && WiFi.getMode() == WIFI_STA && WiFi.status() == WL_CONNECTED) {
|
||||
if(mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED) {
|
||||
mqttHandler->publishTemperatures(&config, &hw);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user