MQTT Button works
This commit is contained in:
parent
5e9e0cccc3
commit
6579a3ba52
|
|
@ -0,0 +1,21 @@
|
|||
import { request } from './request'
|
||||
|
||||
export const publishMqttMessage = (body: {
|
||||
server: string
|
||||
clientId?: string
|
||||
username?: string
|
||||
password?: string
|
||||
qos?: number
|
||||
retain?: boolean
|
||||
message: string
|
||||
topic: string
|
||||
}) =>
|
||||
request(
|
||||
`/api/mqtt/publish`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
},
|
||||
'void'
|
||||
)
|
||||
|
|
@ -84,6 +84,10 @@
|
|||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
&.hidden-title {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.drag-handle {
|
||||
flex: 1;
|
||||
cursor: move;
|
||||
|
|
@ -133,6 +137,21 @@
|
|||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.mqtt-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
|
||||
&.apply-stretch {
|
||||
align-items: stretch;
|
||||
|
||||
> button {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { useConfirmModal } from '@/contexts/ConfirmModalsContext'
|
|||
import {
|
||||
DashboardDialData,
|
||||
DashboardGraphData,
|
||||
DashboardMQTTButtonData,
|
||||
} from '@/utils/dashboard/parseDashboard'
|
||||
import { useForm } from '@/utils/hooks/useForm'
|
||||
import { useState } from 'preact/hooks'
|
||||
|
|
@ -11,6 +12,7 @@ import { useQuery } from 'react-query'
|
|||
import { BoxDefinition } from '../../types'
|
||||
import { DialSettings } from './components/DialSettings'
|
||||
import { GraphSettings } from './components/GraphSettings'
|
||||
import { MQTTButtonSettings } from './components/MQTTButtonSettings'
|
||||
|
||||
type Props = {
|
||||
value: BoxDefinition
|
||||
|
|
@ -63,6 +65,7 @@ export const BoxSettings = ({ value, onSave, onClose, onRemove }: Props) => {
|
|||
<select {...register('type')} required>
|
||||
<option value="graph">Graph</option>
|
||||
<option value="dial">Dial</option>
|
||||
<option value="mqttButton">MQTT Button</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
|
@ -81,6 +84,13 @@ export const BoxSettings = ({ value, onSave, onClose, onRemove }: Props) => {
|
|||
sensors={sensors.data ?? []}
|
||||
/>
|
||||
)}
|
||||
|
||||
{type === 'mqttButton' && (
|
||||
<MQTTButtonSettings
|
||||
value={data as DashboardMQTTButtonData}
|
||||
onChange={setData}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
import { FormCheckboxField } from '@/components/FormCheckboxField'
|
||||
import { FormField } from '@/components/FormField'
|
||||
import { DashboardMQTTButtonData } from '@/utils/dashboard/parseDashboard'
|
||||
import { useForm } from '@/utils/hooks/useForm'
|
||||
import { omit } from '@/utils/omit'
|
||||
|
||||
type Props = {
|
||||
value?: DashboardMQTTButtonData
|
||||
onChange: (data: DashboardMQTTButtonData) => void
|
||||
}
|
||||
|
||||
export const MQTTButtonSettings = ({ value, onChange }: Props) => {
|
||||
const { register } = useForm({
|
||||
defaultValue: () => ({
|
||||
server: '',
|
||||
topic: '',
|
||||
message: '',
|
||||
retain: false,
|
||||
...(value && omit(value, ['type'])),
|
||||
}),
|
||||
onChange: (v) => onChange({ ...v, type: 'mqttButton' }),
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormField
|
||||
name="server"
|
||||
label="MQTT Broker Address"
|
||||
hint="Example: tcp://10.10.1.1:1883"
|
||||
>
|
||||
<input required {...register('server')} />
|
||||
</FormField>
|
||||
<FormField name="clientId" label="Client ID">
|
||||
<input {...register('clientId')} />
|
||||
</FormField>
|
||||
<FormField name="username" label="Username">
|
||||
<input {...register('username')} />
|
||||
</FormField>
|
||||
<FormField name="password" label="Password">
|
||||
<input type="password" {...register('password')} />
|
||||
</FormField>
|
||||
<FormField name="qoc" label="QoS">
|
||||
<select {...register('qos', { type: 'integer' })}>
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
</FormField>
|
||||
<FormCheckboxField name="retain" label="Retain">
|
||||
<input type="checkbox" {...register('retain')} />
|
||||
</FormCheckboxField>
|
||||
<FormField name="topic" label="Topic">
|
||||
<input required {...register('topic')} />
|
||||
</FormField>
|
||||
<FormField name="message" label="Payload">
|
||||
<textarea required {...register('message')} rows={4} />
|
||||
</FormField>
|
||||
<FormCheckboxField
|
||||
name="stretchButton"
|
||||
label="Stretch button to full size"
|
||||
hint="Makes button cover the whole area of the box"
|
||||
>
|
||||
<input type="checkbox" {...register('stretchButton')} />
|
||||
</FormCheckboxField>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import { DashboardMQTTButtonData } from '@/utils/dashboard/parseDashboard'
|
||||
import { EditableBox, EditableBoxProps } from './EditableBox'
|
||||
import { useMutation } from 'react-query'
|
||||
import { publishMqttMessage } from '@/api/mqtt'
|
||||
import { cn } from '@/utils/cn'
|
||||
|
||||
type Props = EditableBoxProps & {
|
||||
data: DashboardMQTTButtonData
|
||||
}
|
||||
|
||||
export const BoxMQTTButtonContent = ({ data, ...boxProps }: Props) => {
|
||||
const pushMutation = useMutation(publishMqttMessage)
|
||||
|
||||
const onClick = () => {
|
||||
pushMutation.mutate({
|
||||
...data,
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<EditableBox {...boxProps} onRefresh={() => null} hiddenTitle>
|
||||
<div className={cn('mqtt-button', data.stretchButton && 'apply-stretch')}>
|
||||
<button onClick={onClick} disabled={pushMutation.isLoading}>
|
||||
{boxProps.box.title ?? 'BUTTON'}
|
||||
</button>
|
||||
</div>
|
||||
</EditableBox>
|
||||
)
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import { useWindowEvent } from '@/utils/hooks/useWindowEvent'
|
|||
import { ComponentChild } from 'preact'
|
||||
import { useState } from 'preact/hooks'
|
||||
import { BoxSettings } from '../../BoxSettings/BoxSettings'
|
||||
import { cn } from '@/utils/cn'
|
||||
|
||||
export type EditableBoxProps = {
|
||||
box: BoxDefinition
|
||||
|
|
@ -19,11 +20,13 @@ export type EditableBoxProps = {
|
|||
}
|
||||
|
||||
type EditableBoxPropsWithExtra = EditableBoxProps & {
|
||||
hiddenTitle?: boolean
|
||||
children: ComponentChild
|
||||
onRefresh: () => void
|
||||
}
|
||||
|
||||
export const EditableBox = ({
|
||||
hiddenTitle,
|
||||
box,
|
||||
children,
|
||||
onPosition,
|
||||
|
|
@ -135,9 +138,9 @@ export const EditableBox = ({
|
|||
}
|
||||
>
|
||||
<div className="box" style={{ height: '100%' }}>
|
||||
<div className="header">
|
||||
<div className={cn('header', hiddenTitle && 'hidden-title')}>
|
||||
<div className="drag-handle" onMouseDown={handleMouseDown}>
|
||||
<div className="name">{box.title || ''}</div>
|
||||
{!hiddenTitle && <div className="name">{box.title || ''}</div>}
|
||||
</div>
|
||||
<div className="actions">
|
||||
<div className="action" onClick={onRefresh}>
|
||||
|
|
@ -148,6 +151,7 @@ export const EditableBox = ({
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="body">{children}</div>
|
||||
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { BoxDialContent } from './BoxDialContent'
|
||||
import { BoxGraphContent } from './BoxGraphContent'
|
||||
import { BoxMQTTButtonContent } from './BoxMQTTButtonContent'
|
||||
import { EditableBox, EditableBoxProps } from './EditableBox'
|
||||
|
||||
export const GeneralBox = (props: EditableBoxProps) => {
|
||||
|
|
@ -8,10 +9,12 @@ export const GeneralBox = (props: EditableBoxProps) => {
|
|||
return <BoxDialContent {...props} data={props.box.data} />
|
||||
case 'graph':
|
||||
return <BoxGraphContent {...props} data={props.box.data} />
|
||||
case 'mqttButton':
|
||||
return <BoxMQTTButtonContent {...props} data={props.box.data} />
|
||||
default:
|
||||
return (
|
||||
<EditableBox {...props} onRefresh={() => null}>
|
||||
<></>
|
||||
<button onClick={() => props.onEdit(props.box)}>Pick a type</button>
|
||||
</EditableBox>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export type DashboardContentBox = {
|
|||
w: number
|
||||
h: number
|
||||
title?: string
|
||||
data?: DashboardGraphData | DashboardDialData
|
||||
data?: DashboardGraphData | DashboardDialData | DashboardMQTTButtonData
|
||||
}
|
||||
|
||||
export type DashboardGraphData = {
|
||||
|
|
@ -44,6 +44,19 @@ export type DashboardDialData = {
|
|||
fontSize?: number
|
||||
}
|
||||
|
||||
export type DashboardMQTTButtonData = {
|
||||
type: 'mqttButton'
|
||||
server: string
|
||||
clientId?: string
|
||||
username?: string
|
||||
password?: string
|
||||
qos?: number
|
||||
retain?: boolean
|
||||
message: string
|
||||
topic: string
|
||||
stretchButton?: boolean
|
||||
}
|
||||
|
||||
export const parseDashboard = (input: string) => {
|
||||
const data = JSON.parse(input) as DashboardContent
|
||||
const migrations = getDashboardMigrations(data.version)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
type putMQTTPublishBody struct {
|
||||
Server string `json:"server" binding:"required"`
|
||||
ClientId string `json:"clientId" binding:"required"`
|
||||
ClientId string `json:"clientId"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Retain *bool `json:"retain"`
|
||||
|
|
|
|||
Loading…
Reference in New Issue