💣 Removes mqtt support
This commit is contained in:
@@ -1,9 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import MQTT from './MQTT.svelte';
|
|
||||||
import MqttConfig from './MQTTConfig.svelte';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="mx-0 my-1 flex flex-col space-y-4 sm:mx-8 sm:my-8">
|
|
||||||
<MQTT />
|
|
||||||
<MqttConfig />
|
|
||||||
</div>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import type { PageLoad } from './$types';
|
|
||||||
|
|
||||||
export const load = (async () => {
|
|
||||||
return {
|
|
||||||
title: "MQTT"
|
|
||||||
};
|
|
||||||
}) satisfies PageLoad;
|
|
||||||
@@ -1,267 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { onMount, onDestroy } from 'svelte';
|
|
||||||
import { slide } from 'svelte/transition';
|
|
||||||
import { cubicOut } from 'svelte/easing';
|
|
||||||
import InputPassword from '$lib/components/InputPassword.svelte';
|
|
||||||
import SettingsCard from '$lib/components/SettingsCard.svelte';
|
|
||||||
import { user } from '$lib/stores/user';
|
|
||||||
import { page } from '$app/stores';
|
|
||||||
import { notifications } from '$lib/components/toasts/notifications';
|
|
||||||
import Spinner from '$lib/components/Spinner.svelte';
|
|
||||||
import Collapsible from '$lib/components/Collapsible.svelte';
|
|
||||||
import MQTT from '~icons/tabler/topology-star-3';
|
|
||||||
import Client from '~icons/tabler/robot';
|
|
||||||
import type { MQTTSettings, MQTTStatus } from '$lib/models';
|
|
||||||
import { api } from '$lib/api';
|
|
||||||
|
|
||||||
let mqttSettings: MQTTSettings;
|
|
||||||
let mqttStatus: MQTTStatus;
|
|
||||||
|
|
||||||
let formField: any;
|
|
||||||
|
|
||||||
async function getMQTTStatus() {
|
|
||||||
const result = await api.get<MQTTStatus>('/api/mqttStatus');
|
|
||||||
if (result.isErr()){
|
|
||||||
console.error('Error:', result.inner);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mqttStatus = result.inner
|
|
||||||
return mqttStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getMQTTSettings() {
|
|
||||||
const result = await api.get<MQTTSettings>('/api/mqttSettings');
|
|
||||||
if (result.isErr()){
|
|
||||||
console.error('Error:', result.inner);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mqttSettings = result.inner
|
|
||||||
return mqttSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
const interval = setInterval(async () => {
|
|
||||||
getMQTTStatus();
|
|
||||||
}, 5000);
|
|
||||||
|
|
||||||
onDestroy(() => clearInterval(interval));
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
if (!$page.data.features.security || $user.admin) {
|
|
||||||
getMQTTSettings();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let formErrors = {
|
|
||||||
host: false,
|
|
||||||
port: false,
|
|
||||||
keep_alive: false,
|
|
||||||
topic_length: false
|
|
||||||
};
|
|
||||||
|
|
||||||
async function postMQTTSettings(data: MQTTSettings) {
|
|
||||||
const result = await api.post<MQTTSettings>('/api/mqttSettings', data);
|
|
||||||
if (result.isErr()){
|
|
||||||
console.error('Error:', result.inner);
|
|
||||||
notifications.error('User not authorized.', 3000);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
notifications.success('MQTT settings updated.', 3000);
|
|
||||||
mqttSettings = result.inner
|
|
||||||
return mqttSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSubmitMQTT() {
|
|
||||||
let valid = true;
|
|
||||||
|
|
||||||
// Validate Server URI
|
|
||||||
const regexExpURL =
|
|
||||||
/(([-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4})|(\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b))(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/i;
|
|
||||||
|
|
||||||
if (!regexExpURL.test(mqttSettings.uri)) {
|
|
||||||
valid = false;
|
|
||||||
formErrors.host = true;
|
|
||||||
} else {
|
|
||||||
formErrors.host = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate if port is a number and within the right range
|
|
||||||
let keepalive = Number(mqttSettings.keep_alive);
|
|
||||||
if (1 <= keepalive && keepalive <= 600) {
|
|
||||||
formErrors.keep_alive = false;
|
|
||||||
} else {
|
|
||||||
formErrors.keep_alive = true;
|
|
||||||
valid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Submit JSON to REST API
|
|
||||||
if (valid) {
|
|
||||||
postMQTTSettings(mqttSettings);
|
|
||||||
//alert('Form Valid');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<SettingsCard collapsible={false}>
|
|
||||||
<MQTT slot="icon" class="lex-shrink-0 mr-2 h-6 w-6 self-end" />
|
|
||||||
<span slot="title">MQTT</span>
|
|
||||||
<div class="w-full overflow-x-auto">
|
|
||||||
{#await getMQTTStatus()}
|
|
||||||
<Spinner />
|
|
||||||
{:then nothing}
|
|
||||||
<div
|
|
||||||
class="flex w-full flex-col space-y-1"
|
|
||||||
transition:slide|local={{ duration: 300, easing: cubicOut }}
|
|
||||||
>
|
|
||||||
<div class="rounded-box bg-base-100 flex items-center space-x-3 px-4 py-2">
|
|
||||||
<div
|
|
||||||
class="mask mask-hexagon h-auto w-10 {mqttStatus.connected === true
|
|
||||||
? 'bg-success'
|
|
||||||
: 'bg-error'}"
|
|
||||||
>
|
|
||||||
<MQTT
|
|
||||||
class="h-auto w-full scale-75 {mqttStatus.connected === true
|
|
||||||
? 'text-success-content'
|
|
||||||
: 'text-error-content'}"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="font-bold">Status</div>
|
|
||||||
<div class="text-sm opacity-75">
|
|
||||||
{#if mqttStatus.connected}
|
|
||||||
Connected
|
|
||||||
{:else if !mqttStatus.enabled}
|
|
||||||
MQTT Disabled
|
|
||||||
{:else}
|
|
||||||
{mqttStatus.last_error}
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="rounded-box bg-base-100 flex items-center space-x-3 px-4 py-2">
|
|
||||||
<div class="mask mask-hexagon bg-primary h-auto w-10">
|
|
||||||
<Client class="text-primary-content h-auto w-full scale-75" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="font-bold">Client ID</div>
|
|
||||||
<div class="text-sm opacity-75">
|
|
||||||
{mqttStatus.client_id}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/await}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if !$page.data.features.security || $user.admin}
|
|
||||||
<Collapsible open={false} class="shadow-lg" on:closed={getMQTTSettings}>
|
|
||||||
<span slot="title">Change MQTT Settings</span>
|
|
||||||
|
|
||||||
<form on:submit|preventDefault={handleSubmitMQTT} novalidate bind:this={formField}>
|
|
||||||
<div class="grid w-full grid-cols-1 content-center gap-x-4 px-4 sm:grid-cols-2">
|
|
||||||
<!-- Enable -->
|
|
||||||
<label class="label inline-flex cursor-pointer content-end justify-start gap-4">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
bind:checked={mqttSettings.enabled}
|
|
||||||
class="checkbox checkbox-primary"
|
|
||||||
/>
|
|
||||||
<span>Enable MQTT</span>
|
|
||||||
</label>
|
|
||||||
<div class="hidden sm:block" />
|
|
||||||
<!-- URI -->
|
|
||||||
<div class="sm:col-span-2">
|
|
||||||
<label class="label" for="host">
|
|
||||||
<span class="label-text text-md">URI</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="input input-bordered invalid:border-error w-full invalid:border-2 {formErrors.host
|
|
||||||
? 'border-error border-2'
|
|
||||||
: ''}"
|
|
||||||
bind:value={mqttSettings.uri}
|
|
||||||
id="host"
|
|
||||||
min="3"
|
|
||||||
max="64"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<label class="label" for="host">
|
|
||||||
<span class="label-text-alt text-error {formErrors.host ? '' : 'hidden'}"
|
|
||||||
>Must be a valid URI</span
|
|
||||||
>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<!-- Username -->
|
|
||||||
<div>
|
|
||||||
<label class="label" for="user">
|
|
||||||
<span class="label-text text-md">Username</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="input input-bordered w-full"
|
|
||||||
bind:value={mqttSettings.username}
|
|
||||||
id="user"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<!-- Password -->
|
|
||||||
<div>
|
|
||||||
<label class="label" for="pwd">
|
|
||||||
<span class="label-text text-md">Password</span>
|
|
||||||
</label>
|
|
||||||
<InputPassword bind:value={mqttSettings.password} id="pwd" />
|
|
||||||
</div>
|
|
||||||
<!-- Client ID -->
|
|
||||||
<div>
|
|
||||||
<label class="label" for="clientid">
|
|
||||||
<span class="label-text text-md">Client ID</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="input input-bordered w-full"
|
|
||||||
bind:value={mqttSettings.client_id}
|
|
||||||
id="clientid"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<!-- Keep Alive -->
|
|
||||||
<div>
|
|
||||||
<label class="label" for="keepalive">
|
|
||||||
<span class="label-text text-md">Keep Alive</span>
|
|
||||||
</label>
|
|
||||||
<label for="keepalive" class="input-group">
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="600"
|
|
||||||
class="input input-bordered invalid:border-error w-full invalid:border-2 {formErrors.keep_alive
|
|
||||||
? 'border-error border-2'
|
|
||||||
: ''}"
|
|
||||||
bind:value={mqttSettings.keep_alive}
|
|
||||||
id="keepalive"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<span>Seconds</span>
|
|
||||||
</label>
|
|
||||||
<label for="keepalive" class="label"
|
|
||||||
><span class="label-text-alt text-error {formErrors.keep_alive ? '' : 'hidden'}"
|
|
||||||
>Must be between 1 and 600 seconds</span
|
|
||||||
></label
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<!-- Clean Session -->
|
|
||||||
<label class="label inline-flex cursor-pointer content-end justify-start gap-4">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
bind:checked={mqttSettings.clean_session}
|
|
||||||
class="checkbox checkbox-primary"
|
|
||||||
/>
|
|
||||||
<span class="">Clean Session?</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="divider mb-2 mt-0" />
|
|
||||||
<div class="mx-4 flex flex-wrap justify-end gap-2">
|
|
||||||
<button class="btn btn-primary" type="submit">Apply Settings</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</Collapsible>
|
|
||||||
{/if}
|
|
||||||
</SettingsCard>
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { slide } from 'svelte/transition';
|
|
||||||
import { cubicOut } from 'svelte/easing';
|
|
||||||
import SettingsCard from '$lib/components/SettingsCard.svelte';
|
|
||||||
import { notifications } from '$lib/components/toasts/notifications';
|
|
||||||
import Spinner from '$lib/components/Spinner.svelte';
|
|
||||||
import MQTT from '~icons/tabler/topology-star-3';
|
|
||||||
import Info from '~icons/tabler/info-circle';
|
|
||||||
import type { BrokerSettings } from '$lib/types/models';
|
|
||||||
import { api } from '$lib/api';
|
|
||||||
|
|
||||||
let brokerSettings: BrokerSettings;
|
|
||||||
|
|
||||||
let formField: any;
|
|
||||||
|
|
||||||
async function getBrokerSettings() {
|
|
||||||
const result = await api.get<BrokerSettings>('/api/brokerSettings');
|
|
||||||
if (result.isErr()){
|
|
||||||
console.error('Error:', result.inner);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
brokerSettings = result.inner
|
|
||||||
}
|
|
||||||
|
|
||||||
let formErrors = {
|
|
||||||
uid: false,
|
|
||||||
path: false,
|
|
||||||
name: false
|
|
||||||
};
|
|
||||||
|
|
||||||
async function postBrokerSettings() {
|
|
||||||
const result = await api.post<BrokerSettings>('/api/brokerSettings', brokerSettings);
|
|
||||||
if (result.isErr()){
|
|
||||||
console.error('Error:', result.inner);
|
|
||||||
notifications.error('User not authorized.', 3000);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
notifications.success('Broker settings updated.', 3000);
|
|
||||||
brokerSettings = result.inner
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSubmitBroker() {
|
|
||||||
let valid = true;
|
|
||||||
|
|
||||||
// Validate unique ID
|
|
||||||
if (brokerSettings.unique_id.length < 3 || brokerSettings.unique_id.length > 32) {
|
|
||||||
valid = false;
|
|
||||||
formErrors.uid = true;
|
|
||||||
} else {
|
|
||||||
formErrors.uid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate name
|
|
||||||
if (brokerSettings.name.length < 3 || brokerSettings.name.length > 32) {
|
|
||||||
valid = false;
|
|
||||||
formErrors.name = true;
|
|
||||||
} else {
|
|
||||||
formErrors.name = false;
|
|
||||||
}
|
|
||||||
// Validate MQTT Path
|
|
||||||
if (brokerSettings.mqtt_path.length > 64) {
|
|
||||||
valid = false;
|
|
||||||
formErrors.path = true;
|
|
||||||
} else {
|
|
||||||
formErrors.path = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Submit JSON to REST API
|
|
||||||
if (valid) {
|
|
||||||
postBrokerSettings();
|
|
||||||
//alert('Form Valid');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<SettingsCard collapsible={true} open={false}>
|
|
||||||
<MQTT slot="icon" class="lex-shrink-0 mr-2 h-6 w-6 self-end" />
|
|
||||||
<span slot="title">MQTT Broker Settings</span>
|
|
||||||
<div class="w-full overflow-x-auto">
|
|
||||||
{#await getBrokerSettings()}
|
|
||||||
<Spinner />
|
|
||||||
{:then nothing}
|
|
||||||
<form
|
|
||||||
on:submit|preventDefault={handleSubmitBroker}
|
|
||||||
novalidate
|
|
||||||
bind:this={formField}
|
|
||||||
transition:slide|local={{ duration: 300, easing: cubicOut }}
|
|
||||||
>
|
|
||||||
<div class="alert alert-info my-2 shadow-lg">
|
|
||||||
<Info class="h-6 w-6 flex-shrink-0 stroke-current" />
|
|
||||||
<span
|
|
||||||
>The LED is controllable via MQTT with the demo project designed to work with Home
|
|
||||||
Assistant's auto discovery feature.</span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="grid w-full grid-cols-1 content-center gap-x-4 px-4">
|
|
||||||
<div>
|
|
||||||
<label class="label" for="uid">
|
|
||||||
<span class="label-text text-md">Unique ID</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="input input-bordered invalid:border-error w-full invalid:border-2 {formErrors.uid
|
|
||||||
? 'border-error border-2'
|
|
||||||
: ''}"
|
|
||||||
bind:value={brokerSettings.unique_id}
|
|
||||||
id="uid"
|
|
||||||
min="3"
|
|
||||||
max="32"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<label class="label" for="uid">
|
|
||||||
<span class="label-text-alt text-error {formErrors.uid ? '' : 'hidden'}"
|
|
||||||
>Unique ID must be between 3 and 32 characters long</span
|
|
||||||
>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="label" for="name">
|
|
||||||
<span class="label-text text-md">Name</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="input input-bordered invalid:border-error w-full invalid:border-2 {formErrors.name
|
|
||||||
? 'border-error border-2'
|
|
||||||
: ''}"
|
|
||||||
bind:value={brokerSettings.name}
|
|
||||||
id="name"
|
|
||||||
min="3"
|
|
||||||
max="32"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<label class="label" for="name">
|
|
||||||
<span class="label-text-alt text-error {formErrors.name ? '' : 'hidden'}"
|
|
||||||
>Name must be between 3 and 32 characters long</span
|
|
||||||
>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="label" for="path">
|
|
||||||
<span class="label-text text-md">MQTT Path</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="input input-bordered invalid:border-error w-full invalid:border-2 {formErrors.path
|
|
||||||
? 'border-error border-2'
|
|
||||||
: ''}"
|
|
||||||
bind:value={brokerSettings.mqtt_path}
|
|
||||||
id="path"
|
|
||||||
min="0"
|
|
||||||
max="64"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<label class="label" for="path">
|
|
||||||
<span class="label-text-alt text-error {formErrors.path ? '' : 'hidden'}"
|
|
||||||
>MQTT path is limited to 64 characters</span
|
|
||||||
>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="divider mb-2 mt-0" />
|
|
||||||
<div class="mx-4 flex flex-wrap justify-end gap-2">
|
|
||||||
<button class="btn btn-primary" type="submit">Apply Settings</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
{/await}
|
|
||||||
</div>
|
|
||||||
</SettingsCard>
|
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
import Avatar from '~icons/mdi/user-circle';
|
import Avatar from '~icons/mdi/user-circle';
|
||||||
import Logout from '~icons/mdi/logout';
|
import Logout from '~icons/mdi/logout';
|
||||||
import Copyright from '~icons/mdi/copyright';
|
import Copyright from '~icons/mdi/copyright';
|
||||||
import MQTT from '~icons/tabler/topology-star-3';
|
|
||||||
import NTP from '~icons/mdi/clock-check';
|
import NTP from '~icons/mdi/clock-check';
|
||||||
import Metrics from '~icons/mdi/report-bar';
|
import Metrics from '~icons/mdi/report-bar';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
@@ -85,13 +84,6 @@
|
|||||||
icon: Remote,
|
icon: Remote,
|
||||||
feature: $page.data.features.mqtt || $page.data.features.ntp,
|
feature: $page.data.features.mqtt || $page.data.features.ntp,
|
||||||
submenu: [
|
submenu: [
|
||||||
{
|
|
||||||
title: 'MQTT',
|
|
||||||
icon: MQTT,
|
|
||||||
href: '/connections/mqtt',
|
|
||||||
feature: $page.data.features.mqtt,
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: 'NTP',
|
title: 'NTP',
|
||||||
icon: NTP,
|
icon: NTP,
|
||||||
|
|||||||
@@ -42,17 +42,6 @@ build_flags =
|
|||||||
-D FACTORY_OTA_PASSWORD=\"spot-leika\"
|
-D FACTORY_OTA_PASSWORD=\"spot-leika\"
|
||||||
-D FACTORY_OTA_ENABLED=true
|
-D FACTORY_OTA_ENABLED=true
|
||||||
|
|
||||||
; MQTT settings
|
|
||||||
-D FACTORY_MQTT_ENABLED=false
|
|
||||||
-D FACTORY_MQTT_URI=\"test.mosquitto.org\"
|
|
||||||
-D FACTORY_MQTT_PORT=1883
|
|
||||||
-D FACTORY_MQTT_USERNAME=\"\" ; supports placeholders
|
|
||||||
-D FACTORY_MQTT_PASSWORD=\"\"
|
|
||||||
-D FACTORY_MQTT_CLIENT_ID=\"#{platform}-#{unique_id}\" ; supports placeholders
|
|
||||||
-D FACTORY_MQTT_KEEP_ALIVE=60
|
|
||||||
-D FACTORY_MQTT_CLEAN_SESSION=true
|
|
||||||
-D FACTORY_MQTT_MAX_TOPIC_LENGTH=128
|
|
||||||
|
|
||||||
; JWT Secret
|
; JWT Secret
|
||||||
-D FACTORY_JWT_SECRET=\"#{random}-#{random}\" ; supports placeholders
|
-D FACTORY_JWT_SECRET=\"#{random}-#{random}\" ; supports placeholders
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ build_flags =
|
|||||||
-D FT_BATTERY=0
|
-D FT_BATTERY=0
|
||||||
-D FT_NTP=1
|
-D FT_NTP=1
|
||||||
-D FT_SECURITY=0
|
-D FT_SECURITY=0
|
||||||
-D FT_MQTT=0
|
|
||||||
-D FT_SLEEP=0
|
-D FT_SLEEP=0
|
||||||
-D FT_UPLOAD_FIRMWARE=0
|
-D FT_UPLOAD_FIRMWARE=0
|
||||||
-D FT_DOWNLOAD_FIRMWARE=0
|
-D FT_DOWNLOAD_FIRMWARE=0
|
||||||
|
|||||||
@@ -40,10 +40,6 @@ ESP32SvelteKit::ESP32SvelteKit(PsychicHttpServer *server,
|
|||||||
_downloadFirmwareService(server, &_securitySettingsService, &_socket,
|
_downloadFirmwareService(server, &_securitySettingsService, &_socket,
|
||||||
&_taskManager),
|
&_taskManager),
|
||||||
#endif
|
#endif
|
||||||
#if FT_ENABLED(FT_MQTT)
|
|
||||||
_mqttSettingsService(server, &ESPFS, &_securitySettingsService),
|
|
||||||
_mqttStatus(server, &_mqttSettingsService, &_securitySettingsService),
|
|
||||||
#endif
|
|
||||||
#if FT_ENABLED(FT_SECURITY)
|
#if FT_ENABLED(FT_SECURITY)
|
||||||
_authenticationService(server, &_securitySettingsService),
|
_authenticationService(server, &_securitySettingsService),
|
||||||
#endif
|
#endif
|
||||||
@@ -189,10 +185,6 @@ void ESP32SvelteKit::startServices() {
|
|||||||
_ntpSettingsService.begin();
|
_ntpSettingsService.begin();
|
||||||
_ntpStatus.begin();
|
_ntpStatus.begin();
|
||||||
#endif
|
#endif
|
||||||
#if FT_ENABLED(FT_MQTT)
|
|
||||||
_mqttSettingsService.begin();
|
|
||||||
_mqttStatus.begin();
|
|
||||||
#endif
|
|
||||||
#if FT_ENABLED(FT_SECURITY)
|
#if FT_ENABLED(FT_SECURITY)
|
||||||
_authenticationService.begin();
|
_authenticationService.begin();
|
||||||
_securitySettingsService.begin();
|
_securitySettingsService.begin();
|
||||||
@@ -229,9 +221,6 @@ void IRAM_ATTR ESP32SvelteKit::_loop() {
|
|||||||
while (1) {
|
while (1) {
|
||||||
_wifiSettingsService.loop();
|
_wifiSettingsService.loop();
|
||||||
_apSettingsService.loop();
|
_apSettingsService.loop();
|
||||||
#if FT_ENABLED(FT_MQTT)
|
|
||||||
_mqttSettingsService.loop();
|
|
||||||
#endif
|
|
||||||
#if FT_ENABLED(FT_ANALYTICS)
|
#if FT_ENABLED(FT_ANALYTICS)
|
||||||
_analyticsService.loop();
|
_analyticsService.loop();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -33,8 +33,6 @@
|
|||||||
#include <FactoryResetService.h>
|
#include <FactoryResetService.h>
|
||||||
#include <FeaturesService.h>
|
#include <FeaturesService.h>
|
||||||
#include <IMUService.h>
|
#include <IMUService.h>
|
||||||
#include <MqttSettingsService.h>
|
|
||||||
#include <MqttStatus.h>
|
|
||||||
#include <MotionService.h>
|
#include <MotionService.h>
|
||||||
#include <NTPSettingsService.h>
|
#include <NTPSettingsService.h>
|
||||||
#include <CameraService.h>
|
#include <CameraService.h>
|
||||||
@@ -117,18 +115,6 @@ public:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FT_ENABLED(FT_MQTT)
|
|
||||||
StatefulService<MqttSettings> *getMqttSettingsService()
|
|
||||||
{
|
|
||||||
return &_mqttSettingsService;
|
|
||||||
}
|
|
||||||
|
|
||||||
PsychicMqttClient *getMqttClient()
|
|
||||||
{
|
|
||||||
return _mqttSettingsService.getMqttClient();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if FT_ENABLED(FT_SLEEP)
|
#if FT_ENABLED(FT_SLEEP)
|
||||||
SleepService *getSleepService()
|
SleepService *getSleepService()
|
||||||
{
|
{
|
||||||
@@ -232,10 +218,6 @@ private:
|
|||||||
#if FT_ENABLED(FT_DOWNLOAD_FIRMWARE)
|
#if FT_ENABLED(FT_DOWNLOAD_FIRMWARE)
|
||||||
DownloadFirmwareService _downloadFirmwareService;
|
DownloadFirmwareService _downloadFirmwareService;
|
||||||
#endif
|
#endif
|
||||||
#if FT_ENABLED(FT_MQTT)
|
|
||||||
MqttSettingsService _mqttSettingsService;
|
|
||||||
MqttStatus _mqttStatus;
|
|
||||||
#endif
|
|
||||||
#if FT_ENABLED(FT_SECURITY)
|
#if FT_ENABLED(FT_SECURITY)
|
||||||
AuthenticationService _authenticationService;
|
AuthenticationService _authenticationService;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -22,11 +22,6 @@
|
|||||||
#define FT_SECURITY 1
|
#define FT_SECURITY 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// mqtt feature on by default
|
|
||||||
#ifndef FT_MQTT
|
|
||||||
#define FT_MQTT 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ntp feature on by default
|
// ntp feature on by default
|
||||||
#ifndef FT_NTP
|
#ifndef FT_NTP
|
||||||
#define FT_NTP 1
|
#define FT_NTP 1
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ void FeaturesService::begin() {
|
|||||||
JsonObject root = response.getRoot();
|
JsonObject root = response.getRoot();
|
||||||
|
|
||||||
root["security"] = FT_SECURITY;
|
root["security"] = FT_SECURITY;
|
||||||
root["mqtt"] = FT_MQTT;
|
|
||||||
root["ntp"] = FT_NTP;
|
root["ntp"] = FT_NTP;
|
||||||
root["upload_firmware"] = FT_UPLOAD_FIRMWARE;
|
root["upload_firmware"] = FT_UPLOAD_FIRMWARE;
|
||||||
root["download_firmware"] = FT_DOWNLOAD_FIRMWARE;
|
root["download_firmware"] = FT_DOWNLOAD_FIRMWARE;
|
||||||
|
|||||||
@@ -1,136 +0,0 @@
|
|||||||
#ifndef MqttEndpoint_h
|
|
||||||
#define MqttEndpoint_h
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 - 2024 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <PsychicMqttClient.h>
|
|
||||||
#include <StatefulService.h>
|
|
||||||
|
|
||||||
#define MQTT_ORIGIN_ID "mqtt"
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class MqttEndpoint {
|
|
||||||
public:
|
|
||||||
MqttEndpoint(JsonStateReader<T> stateReader,
|
|
||||||
JsonStateUpdater<T> stateUpdater,
|
|
||||||
StatefulService<T> *statefulService,
|
|
||||||
PsychicMqttClient *mqttClient, const String &pubTopic = "",
|
|
||||||
const String &subTopic = "", bool retain = false)
|
|
||||||
: _stateReader(stateReader),
|
|
||||||
_stateUpdater(stateUpdater),
|
|
||||||
_statefulService(statefulService),
|
|
||||||
_mqttClient(mqttClient),
|
|
||||||
_pubTopic(pubTopic),
|
|
||||||
_subTopic(subTopic),
|
|
||||||
_retain(retain),
|
|
||||||
_bufferSize(bufferSize)
|
|
||||||
|
|
||||||
{
|
|
||||||
_statefulService->addUpdateHandler(
|
|
||||||
[&](const String &originId) { publish(); }, false);
|
|
||||||
|
|
||||||
_mqttClient->onConnect(std::bind(&MqttEndpoint::onConnect, this));
|
|
||||||
|
|
||||||
_mqttClient->onMessage(
|
|
||||||
std::bind(&MqttEndpoint::onMqttMessage, this, std::placeholders::_1,
|
|
||||||
std::placeholders::_2, std::placeholders::_3,
|
|
||||||
std::placeholders::_4, std::placeholders::_5));
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
void configureTopics(const String &pubTopic, const String &subTopic) {
|
|
||||||
setSubTopic(subTopic);
|
|
||||||
setPubTopic(pubTopic);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSubTopic(const String &subTopic) {
|
|
||||||
if (!_subTopic.equals(subTopic)) {
|
|
||||||
// unsubscribe from the existing topic if one was set
|
|
||||||
if (_subTopic.length() > 0) {
|
|
||||||
_mqttClient->unsubscribe(_subTopic.c_str());
|
|
||||||
}
|
|
||||||
// set the new topic and re-configure the subscription
|
|
||||||
_subTopic = subTopic;
|
|
||||||
subscribe();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPubTopic(const String &pubTopic) {
|
|
||||||
_pubTopic = pubTopic;
|
|
||||||
publish();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRetain(const bool retain) {
|
|
||||||
_retain = retain;
|
|
||||||
publish();
|
|
||||||
}
|
|
||||||
|
|
||||||
void publish() {
|
|
||||||
if (_pubTopic.length() > 0 && _mqttClient->connected()) {
|
|
||||||
// serialize to json doc
|
|
||||||
JsonDocument json;
|
|
||||||
JsonObject jsonObject = json.to<JsonObject>();
|
|
||||||
_statefulService->read(jsonObject, _stateReader);
|
|
||||||
|
|
||||||
// serialize to string
|
|
||||||
String payload;
|
|
||||||
serializeJson(json, payload);
|
|
||||||
|
|
||||||
// publish the payload
|
|
||||||
_mqttClient->publish(_pubTopic.c_str(), 0, _retain,
|
|
||||||
payload.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PsychicMqttClient *getMqttClient() { return _mqttClient; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
StatefulService<T> *_statefulService;
|
|
||||||
PsychicMqttClient *_mqttClient;
|
|
||||||
JsonStateUpdater<T> _stateUpdater;
|
|
||||||
JsonStateReader<T> _stateReader;
|
|
||||||
String _subTopic;
|
|
||||||
String _pubTopic;
|
|
||||||
bool _retain;
|
|
||||||
|
|
||||||
void onMqttMessage(char *topic, char *payload, int retain, int qos,
|
|
||||||
bool dup) {
|
|
||||||
// we only care about the topic we are watching in this class
|
|
||||||
if (strcmp(_subTopic.c_str(), topic)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// deserialize from string
|
|
||||||
JsonDocument json;
|
|
||||||
DeserializationError error = deserializeJson(json, payload);
|
|
||||||
if (!error && json.is<JsonObject>()) {
|
|
||||||
JsonObject jsonObject = json.as<JsonObject>();
|
|
||||||
_statefulService->update(jsonObject, _stateUpdater, MQTT_ORIGIN_ID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void onConnect() {
|
|
||||||
subscribe();
|
|
||||||
publish();
|
|
||||||
}
|
|
||||||
|
|
||||||
void subscribe() {
|
|
||||||
if (_subTopic.length() > 0) {
|
|
||||||
_mqttClient->subscribe(_subTopic.c_str(), 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // end MqttEndpoint
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
#ifndef MqttPubSub_h
|
|
||||||
#define MqttPubSub_h
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 - 2024 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <StatefulService.h>
|
|
||||||
#include <PsychicMqttClient.h>
|
|
||||||
|
|
||||||
#define MQTT_ORIGIN_ID "mqtt"
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class MqttPubSub
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MqttPubSub(JsonStateReader<T> stateReader,
|
|
||||||
JsonStateUpdater<T> stateUpdater,
|
|
||||||
StatefulService<T> *statefulService,
|
|
||||||
PsychicMqttClient *mqttClient,
|
|
||||||
const String &pubTopic = "",
|
|
||||||
const String &subTopic = "",
|
|
||||||
bool retain = false,
|
|
||||||
size_t bufferSize = DEFAULT_BUFFER_SIZE) : _stateReader(stateReader),
|
|
||||||
_stateUpdater(stateUpdater),
|
|
||||||
_statefulService(statefulService),
|
|
||||||
_mqttClient(mqttClient),
|
|
||||||
_pubTopic(pubTopic),
|
|
||||||
_subTopic(subTopic),
|
|
||||||
_retain(retain),
|
|
||||||
_bufferSize(bufferSize)
|
|
||||||
|
|
||||||
{
|
|
||||||
_statefulService->addUpdateHandler([&](const String &originId)
|
|
||||||
{ publish(); },
|
|
||||||
false);
|
|
||||||
|
|
||||||
_mqttClient->onConnect(std::bind(&MqttPubSub::onConnect, this));
|
|
||||||
|
|
||||||
_mqttClient->onMessage(std::bind(&MqttPubSub::onMqttMessage,
|
|
||||||
this,
|
|
||||||
std::placeholders::_1,
|
|
||||||
std::placeholders::_2,
|
|
||||||
std::placeholders::_3,
|
|
||||||
std::placeholders::_4,
|
|
||||||
std::placeholders::_5));
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
void configureTopics(const String &pubTopic, const String &subTopic)
|
|
||||||
{
|
|
||||||
setSubTopic(subTopic);
|
|
||||||
setPubTopic(pubTopic);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSubTopic(const String &subTopic)
|
|
||||||
{
|
|
||||||
if (!_subTopic.equals(subTopic))
|
|
||||||
{
|
|
||||||
// unsubscribe from the existing topic if one was set
|
|
||||||
if (_subTopic.length() > 0)
|
|
||||||
{
|
|
||||||
_mqttClient->unsubscribe(_subTopic.c_str());
|
|
||||||
}
|
|
||||||
// set the new topic and re-configure the subscription
|
|
||||||
_subTopic = subTopic;
|
|
||||||
subscribe();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPubTopic(const String &pubTopic)
|
|
||||||
{
|
|
||||||
_pubTopic = pubTopic;
|
|
||||||
publish();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRetain(const bool retain)
|
|
||||||
{
|
|
||||||
_retain = retain;
|
|
||||||
publish();
|
|
||||||
}
|
|
||||||
|
|
||||||
void publish()
|
|
||||||
{
|
|
||||||
if (_pubTopic.length() > 0 && _mqttClient->connected())
|
|
||||||
{
|
|
||||||
// serialize to json doc
|
|
||||||
JsonDocument json;
|
|
||||||
JsonObject jsonObject = json.to<JsonObject>();
|
|
||||||
_statefulService->read(jsonObject, _stateReader);
|
|
||||||
|
|
||||||
// serialize to string
|
|
||||||
String payload;
|
|
||||||
serializeJson(json, payload);
|
|
||||||
|
|
||||||
// publish the payload
|
|
||||||
_mqttClient->publish(_pubTopic.c_str(), 0, _retain, payload.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PsychicMqttClient *getMqttClient()
|
|
||||||
{
|
|
||||||
return _mqttClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
StatefulService<T> *_statefulService;
|
|
||||||
PsychicMqttClient *_mqttClient;
|
|
||||||
JsonStateUpdater<T> _stateUpdater;
|
|
||||||
JsonStateReader<T> _stateReader;
|
|
||||||
String _subTopic;
|
|
||||||
String _pubTopic;
|
|
||||||
bool _retain;
|
|
||||||
|
|
||||||
void onMqttMessage(char *topic,
|
|
||||||
char *payload,
|
|
||||||
int retain,
|
|
||||||
int qos,
|
|
||||||
bool dup)
|
|
||||||
{
|
|
||||||
// we only care about the topic we are watching in this class
|
|
||||||
if (strcmp(_subTopic.c_str(), topic))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// deserialize from string
|
|
||||||
JsonDocument json;
|
|
||||||
DeserializationError error = deserializeJson(json, payload);
|
|
||||||
if (!error && json.is<JsonObject>())
|
|
||||||
{
|
|
||||||
JsonObject jsonObject = json.as<JsonObject>();
|
|
||||||
_statefulService->update(jsonObject, _stateUpdater, MQTT_ORIGIN_ID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void onConnect()
|
|
||||||
{
|
|
||||||
subscribe();
|
|
||||||
publish();
|
|
||||||
}
|
|
||||||
|
|
||||||
void subscribe()
|
|
||||||
{
|
|
||||||
if (_subTopic.length() > 0)
|
|
||||||
{
|
|
||||||
_mqttClient->subscribe(_subTopic.c_str(), 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // end MqttPubSub
|
|
||||||
@@ -1,186 +0,0 @@
|
|||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <MqttSettingsService.h>
|
|
||||||
|
|
||||||
extern const uint8_t rootca_crt_bundle_start[] asm("_binary_src_certs_x509_crt_bundle_bin_start");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retains a copy of the cstr provided in the pointer provided using dynamic allocation.
|
|
||||||
*
|
|
||||||
* Frees the pointer before allocation and leaves it as nullptr if cstr == nullptr.
|
|
||||||
*/
|
|
||||||
static char *retainCstr(const char *cstr, char **ptr)
|
|
||||||
{
|
|
||||||
// free up previously retained value if exists
|
|
||||||
free(*ptr);
|
|
||||||
*ptr = nullptr;
|
|
||||||
|
|
||||||
// dynamically allocate and copy cstr (if non null)
|
|
||||||
if (cstr != nullptr)
|
|
||||||
{
|
|
||||||
*ptr = (char *)malloc(strlen(cstr) + 1);
|
|
||||||
strcpy(*ptr, cstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// return reference to pointer for convenience
|
|
||||||
return *ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
MqttSettingsService::MqttSettingsService(PsychicHttpServer *server,
|
|
||||||
FS *fs,
|
|
||||||
SecurityManager *securityManager) : _server(server),
|
|
||||||
_securityManager(securityManager),
|
|
||||||
_httpEndpoint(MqttSettings::read, MqttSettings::update, this, server, MQTT_SETTINGS_SERVICE_PATH, securityManager),
|
|
||||||
_fsPersistence(MqttSettings::read, MqttSettings::update, this, fs, MQTT_SETTINGS_FILE),
|
|
||||||
_retainedHost(nullptr),
|
|
||||||
_retainedClientId(nullptr),
|
|
||||||
_retainedUsername(nullptr),
|
|
||||||
_retainedPassword(nullptr),
|
|
||||||
_reconfigureMqtt(false),
|
|
||||||
_mqttClient(),
|
|
||||||
_lastError("None")
|
|
||||||
{
|
|
||||||
addUpdateHandler([&](const String &originId)
|
|
||||||
{ onConfigUpdated(); },
|
|
||||||
false);
|
|
||||||
|
|
||||||
_mqttClient.setCACertBundle(rootca_crt_bundle_start);
|
|
||||||
}
|
|
||||||
|
|
||||||
MqttSettingsService::~MqttSettingsService()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void MqttSettingsService::begin()
|
|
||||||
{
|
|
||||||
WiFi.onEvent(
|
|
||||||
std::bind(&MqttSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2),
|
|
||||||
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
|
|
||||||
WiFi.onEvent(std::bind(&MqttSettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2),
|
|
||||||
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP);
|
|
||||||
_mqttClient.onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, std::placeholders::_1));
|
|
||||||
_mqttClient.onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, std::placeholders::_1));
|
|
||||||
_mqttClient.onError(std::bind(&MqttSettingsService::onMqttError, this, std::placeholders::_1));
|
|
||||||
|
|
||||||
_httpEndpoint.begin();
|
|
||||||
_fsPersistence.readFromFS();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MqttSettingsService::loop()
|
|
||||||
{
|
|
||||||
if (_reconfigureMqtt)
|
|
||||||
{
|
|
||||||
// reconfigure MQTT client
|
|
||||||
configureMqtt();
|
|
||||||
|
|
||||||
// clear the reconnection flags
|
|
||||||
_reconfigureMqtt = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MqttSettingsService::isEnabled()
|
|
||||||
{
|
|
||||||
return _state.enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MqttSettingsService::isConnected()
|
|
||||||
{
|
|
||||||
return _mqttClient.connected();
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *MqttSettingsService::getClientId()
|
|
||||||
{
|
|
||||||
// return _mqttClient.getClientId();
|
|
||||||
return _state.clientId.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
PsychicMqttClient *MqttSettingsService::getMqttClient()
|
|
||||||
{
|
|
||||||
return &_mqttClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
String MqttSettingsService::getLastError()
|
|
||||||
{
|
|
||||||
return _lastError;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MqttSettingsService::onMqttConnect(bool sessionPresent)
|
|
||||||
{
|
|
||||||
ESP_LOGI("MQTT", "Connected to MQTT: %s", _mqttClient.getMqttConfig()->uri);
|
|
||||||
_lastError = "None";
|
|
||||||
}
|
|
||||||
|
|
||||||
void MqttSettingsService::onMqttDisconnect(bool sessionPresent)
|
|
||||||
{
|
|
||||||
ESP_LOGI("MQTT", "Disconnected from MQTT.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void MqttSettingsService::onMqttError(esp_mqtt_error_codes_t error)
|
|
||||||
{
|
|
||||||
if (error.error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT)
|
|
||||||
{
|
|
||||||
_lastError = strerror(error.esp_transport_sock_errno);
|
|
||||||
ESP_LOGE("MQTT", "MQTT TCP error: %s", _lastError.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MqttSettingsService::onConfigUpdated()
|
|
||||||
{
|
|
||||||
_reconfigureMqtt = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MqttSettingsService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info)
|
|
||||||
{
|
|
||||||
if (_state.enabled)
|
|
||||||
{
|
|
||||||
ESP_LOGI("MQTT", "WiFi connection established, starting MQTT client.");
|
|
||||||
onConfigUpdated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MqttSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info)
|
|
||||||
{
|
|
||||||
if (_state.enabled)
|
|
||||||
{
|
|
||||||
ESP_LOGI("MQTT", "WiFi connection dropped, stopping MQTT client.");
|
|
||||||
onConfigUpdated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MqttSettingsService::configureMqtt()
|
|
||||||
{
|
|
||||||
// disconnect if currently connected
|
|
||||||
_mqttClient.disconnect();
|
|
||||||
|
|
||||||
// only connect if WiFi is connected and MQTT is enabled
|
|
||||||
if (_state.enabled && WiFi.isConnected())
|
|
||||||
{
|
|
||||||
_mqttClient.setServer(retainCstr(_state.uri.c_str(), &_retainedHost));
|
|
||||||
if (_state.username.length() > 0)
|
|
||||||
{
|
|
||||||
_mqttClient.setCredentials(
|
|
||||||
retainCstr(_state.username.c_str(), &_retainedUsername),
|
|
||||||
retainCstr(_state.password.length() > 0 ? _state.password.c_str() : nullptr, &_retainedPassword));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_mqttClient.setCredentials(retainCstr(nullptr, &_retainedUsername), retainCstr(nullptr, &_retainedPassword));
|
|
||||||
}
|
|
||||||
_mqttClient.setClientId(retainCstr(_state.clientId.c_str(), &_retainedClientId));
|
|
||||||
_mqttClient.setKeepAlive(_state.keepAlive);
|
|
||||||
_mqttClient.setCleanSession(_state.cleanSession);
|
|
||||||
_mqttClient.connect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
#ifndef MqttSettingsService_h
|
|
||||||
#define MqttSettingsService_h
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <StatefulService.h>
|
|
||||||
#include <HttpEndpoint.h>
|
|
||||||
#include <FSPersistence.h>
|
|
||||||
#include <PsychicMqttClient.h>
|
|
||||||
#include <SettingValue.h>
|
|
||||||
#include <WiFi.h>
|
|
||||||
|
|
||||||
#ifndef FACTORY_MQTT_ENABLED
|
|
||||||
#define FACTORY_MQTT_ENABLED false
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FACTORY_MQTT_HOST
|
|
||||||
#define FACTORY_MQTT_HOST "test.mosquitto.org"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FACTORY_MQTT_PORT
|
|
||||||
#define FACTORY_MQTT_PORT 1883
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FACTORY_MQTT_USERNAME
|
|
||||||
#define FACTORY_MQTT_USERNAME ""
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FACTORY_MQTT_PASSWORD
|
|
||||||
#define FACTORY_MQTT_PASSWORD ""
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FACTORY_MQTT_CLIENT_ID
|
|
||||||
#define FACTORY_MQTT_CLIENT_ID "#{platform}-#{unique_id}"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FACTORY_MQTT_KEEP_ALIVE
|
|
||||||
#define FACTORY_MQTT_KEEP_ALIVE 16
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FACTORY_MQTT_CLEAN_SESSION
|
|
||||||
#define FACTORY_MQTT_CLEAN_SESSION true
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FACTORY_MQTT_MAX_TOPIC_LENGTH
|
|
||||||
#define FACTORY_MQTT_MAX_TOPIC_LENGTH 128
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MQTT_SETTINGS_FILE "/config/mqttSettings.json"
|
|
||||||
#define MQTT_SETTINGS_SERVICE_PATH "/api/mqttSettings"
|
|
||||||
|
|
||||||
#define MQTT_RECONNECTION_DELAY 5000
|
|
||||||
|
|
||||||
class MqttSettings
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// host and port - if enabled
|
|
||||||
bool enabled;
|
|
||||||
String uri;
|
|
||||||
|
|
||||||
// username and password
|
|
||||||
String username;
|
|
||||||
String password;
|
|
||||||
|
|
||||||
// client id settings
|
|
||||||
String clientId;
|
|
||||||
|
|
||||||
// connection settings
|
|
||||||
uint16_t keepAlive;
|
|
||||||
bool cleanSession;
|
|
||||||
|
|
||||||
static void read(MqttSettings &settings, JsonObject &root)
|
|
||||||
{
|
|
||||||
root["enabled"] = settings.enabled;
|
|
||||||
root["uri"] = settings.uri;
|
|
||||||
root["username"] = settings.username;
|
|
||||||
root["password"] = settings.password;
|
|
||||||
root["client_id"] = settings.clientId;
|
|
||||||
root["keep_alive"] = settings.keepAlive;
|
|
||||||
root["clean_session"] = settings.cleanSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
static StateUpdateResult update(JsonObject &root, MqttSettings &settings)
|
|
||||||
{
|
|
||||||
settings.enabled = root["enabled"] | FACTORY_MQTT_ENABLED;
|
|
||||||
settings.uri = root["uri"] | FACTORY_MQTT_URI;
|
|
||||||
settings.username = root["username"] | SettingValue::format(FACTORY_MQTT_USERNAME);
|
|
||||||
settings.password = root["password"] | FACTORY_MQTT_PASSWORD;
|
|
||||||
settings.clientId = root["client_id"] | SettingValue::format(FACTORY_MQTT_CLIENT_ID);
|
|
||||||
settings.keepAlive = root["keep_alive"] | FACTORY_MQTT_KEEP_ALIVE;
|
|
||||||
settings.cleanSession = root["clean_session"] | FACTORY_MQTT_CLEAN_SESSION;
|
|
||||||
return StateUpdateResult::CHANGED;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class MqttSettingsService : public StatefulService<MqttSettings>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MqttSettingsService(PsychicHttpServer *server, FS *fs, SecurityManager *securityManager);
|
|
||||||
~MqttSettingsService();
|
|
||||||
|
|
||||||
void begin();
|
|
||||||
void loop();
|
|
||||||
bool isEnabled();
|
|
||||||
bool isConnected();
|
|
||||||
const char *getClientId();
|
|
||||||
String getLastError();
|
|
||||||
PsychicMqttClient *getMqttClient();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onConfigUpdated();
|
|
||||||
|
|
||||||
private:
|
|
||||||
PsychicHttpServer *_server;
|
|
||||||
SecurityManager *_securityManager;
|
|
||||||
HttpEndpoint<MqttSettings> _httpEndpoint;
|
|
||||||
FSPersistence<MqttSettings> _fsPersistence;
|
|
||||||
|
|
||||||
// Pointers to hold retained copies of the mqtt client connection strings.
|
|
||||||
// This is required as AsyncMqttClient holds references to the supplied connection strings.
|
|
||||||
char *_retainedHost;
|
|
||||||
char *_retainedClientId;
|
|
||||||
char *_retainedUsername;
|
|
||||||
char *_retainedPassword;
|
|
||||||
|
|
||||||
// variable to help manage connection
|
|
||||||
bool _reconfigureMqtt;
|
|
||||||
String _lastError;
|
|
||||||
|
|
||||||
// the MQTT client instance
|
|
||||||
PsychicMqttClient _mqttClient;
|
|
||||||
|
|
||||||
void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info);
|
|
||||||
void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
|
|
||||||
|
|
||||||
void onMqttConnect(bool sessionPresent);
|
|
||||||
void onMqttDisconnect(bool sessionPresent);
|
|
||||||
void onMqttError(esp_mqtt_error_codes_t error);
|
|
||||||
void configureMqtt();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // end MqttSettingsService_h
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <MqttStatus.h>
|
|
||||||
|
|
||||||
MqttStatus::MqttStatus(PsychicHttpServer *server,
|
|
||||||
MqttSettingsService *mqttSettingsService,
|
|
||||||
SecurityManager *securityManager) : _server(server),
|
|
||||||
_securityManager(securityManager),
|
|
||||||
_mqttSettingsService(mqttSettingsService)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void MqttStatus::begin()
|
|
||||||
{
|
|
||||||
_server->on(MQTT_STATUS_SERVICE_PATH,
|
|
||||||
HTTP_GET,
|
|
||||||
_securityManager->wrapRequest(std::bind(&MqttStatus::mqttStatus, this, std::placeholders::_1),
|
|
||||||
AuthenticationPredicates::IS_AUTHENTICATED));
|
|
||||||
|
|
||||||
ESP_LOGV("MqttStatus", "Registered GET endpoint: %s", MQTT_STATUS_SERVICE_PATH);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t MqttStatus::mqttStatus(PsychicRequest *request)
|
|
||||||
{
|
|
||||||
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
|
||||||
JsonObject root = response.getRoot();
|
|
||||||
|
|
||||||
root["enabled"] = _mqttSettingsService->isEnabled();
|
|
||||||
root["connected"] = _mqttSettingsService->isConnected();
|
|
||||||
root["client_id"] = _mqttSettingsService->getClientId();
|
|
||||||
root["last_error"] = _mqttSettingsService->getLastError();
|
|
||||||
|
|
||||||
return response.send();
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
#ifndef MqttStatus_h
|
|
||||||
#define MqttStatus_h
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <WiFi.h>
|
|
||||||
|
|
||||||
#include <MqttSettingsService.h>
|
|
||||||
#include <ArduinoJson.h>
|
|
||||||
#include <PsychicHttp.h>
|
|
||||||
#include <SecurityManager.h>
|
|
||||||
|
|
||||||
#define MQTT_STATUS_SERVICE_PATH "/api/mqttStatus"
|
|
||||||
|
|
||||||
class MqttStatus
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MqttStatus(PsychicHttpServer *server, MqttSettingsService *mqttSettingsService, SecurityManager *securityManager);
|
|
||||||
|
|
||||||
void begin();
|
|
||||||
|
|
||||||
private:
|
|
||||||
PsychicHttpServer *_server;
|
|
||||||
SecurityManager *_securityManager;
|
|
||||||
MqttSettingsService *_mqttSettingsService;
|
|
||||||
|
|
||||||
esp_err_t mqttStatus(PsychicRequest *request);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // end MqttStatus_h
|
|
||||||
+12160
-12679
File diff suppressed because it is too large
Load Diff
@@ -81,7 +81,6 @@ test_ignore = test_embedded
|
|||||||
board_build.filesystem = littlefs
|
board_build.filesystem = littlefs
|
||||||
lib_deps =
|
lib_deps =
|
||||||
ArduinoJson@>=7.0.0
|
ArduinoJson@>=7.0.0
|
||||||
https://github.com/theelims/PsychicMqttClient.git#0.1.1
|
|
||||||
teckel12/NewPing@^1.9.7
|
teckel12/NewPing@^1.9.7
|
||||||
jrowberg/I2Cdevlib-MPU6050@^1.0.0
|
jrowberg/I2Cdevlib-MPU6050@^1.0.0
|
||||||
adafruit/Adafruit SSD1306@^2.5.7
|
adafruit/Adafruit SSD1306@^2.5.7
|
||||||
|
|||||||
Reference in New Issue
Block a user