Skip to content

Commit

Permalink
feat(wirepas): show list of nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
coderbyheart committed Feb 5, 2024
1 parent e24bbb3 commit 916a5a0
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 15 deletions.
37 changes: 33 additions & 4 deletions src/DeviceList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@ import styled from 'styled-components'
import { DisconnectedWarning } from './DisconnectedWarning.js'
import { HistoryOnly } from './HistoryOnly.js'
import { Tracker } from './Tracker.js'
import { isNRPlusGateway, isTracker, useDevices } from './context/Devices.js'
import {
DeviceType,
isNRPlusGateway,
isTracker,
isWirepasGateway,
useDevices,
type Device,
} from './context/Devices.js'
import { useSettings } from './context/Settings.js'
import { useHistoryChart } from './context/showHistoryChart.js'
import { NRPlusGatewayTile } from './NRPlusGatewayTile.js'
import { WirepasGatewayTile } from './wirepas/WirepasGatewayTile.js'

const DeviceState = styled.section`
color: var(--color-nordic-light-grey);
Expand Down Expand Up @@ -104,13 +112,27 @@ export const IssuerName = styled.dd`
`

export const DeviceList = () => {
const { devices, lastUpdateTs } = useDevices()
const { devices, lastUpdateTs, type } = useDevices()
const { show: showHistoryChart } = useHistoryChart()
const {
settings: { showFavorites, favorites },
settings: { showFavorites, favorites, enableWirepas5GMeshGateways },
} = useSettings()

const devicesToShow = Object.entries(devices)
const devicesToShow = (
[
...Object.entries(devices),
...Object.entries(devices)
.filter(
([gwId]) =>
type(gwId) === DeviceType.WIREPAS_5G_MESH_GW &&
enableWirepas5GMeshGateways,
)
.map(([gwId, gw]) => [
gwId,
{ ...gw, type: DeviceType.WIREPAS_5G_MESH_GW },
]),
] as [string, Device][]
)
.filter(([deviceId]) => {
if (!showFavorites) return true
return favorites.includes(deviceId)
Expand Down Expand Up @@ -145,6 +167,13 @@ export const DeviceList = () => {
</li>
)
}
if (isWirepasGateway(device)) {
return (
<li>
<WirepasGatewayTile gateway={device} key={device.id} />
</li>
)
}
if (device.history !== undefined)
return (
<li>
Expand Down
17 changes: 17 additions & 0 deletions src/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const Settings = () => {
settings: {
showSettings,
enableTestDevice,
enableWirepas5GMeshGateways,
showFavorites,
showUpdateWarning,
},
Expand Down Expand Up @@ -71,6 +72,22 @@ export const Settings = () => {
Show test device?
</label>
</div>
<div class="form-check mt-2">
<input
class="form-check-input"
type="checkbox"
id="showWirepasGateways"
checked={enableWirepas5GMeshGateways}
onClick={() =>
update({
enableWirepas5GMeshGateways: !enableWirepas5GMeshGateways,
})
}
/>
<label class="form-check-label" htmlFor="showWirepasGateways">
Show Wirepas 5G Mesh Gateways?
</label>
</div>
<h2 class="h4 mt-4">Devices</h2>
<div class="form-check mt-2">
<input
Expand Down
74 changes: 63 additions & 11 deletions src/context/Devices.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,19 @@ export type GeoLocation = {
label?: string
ts: Date
}

export enum DeviceType {
WIREPAS_5G_MESH_GW = 'wirepas-5g-mesh-gateway',
NRPLUS_GW = 'nrplus-gateway',
SOFT_SIM = 'soft-sim',
}
export type Device = {
id: string
state?: Reported
location?: Record<GeoLocationSource, GeoLocation>
history?: Summary
hiddenLocations?: Record<GeoLocationSource, true>
type?: DeviceType
}

// NR+ Gateway
Expand Down Expand Up @@ -183,6 +190,29 @@ export type NRPlusGateway = {
location?: Record<GeoLocationSource, GeoLocation>
}

/**
* Quality of Service
*/
export enum WirepasMeshQOS {
Normal = 0,
High = 1,
}

export type WirepasGatewayNode = {
travelTimeMs: number // e.g. 54
hops: number // e.g. 1
rxTime: string // e.g. '2024-02-05T13:44:06.050Z'
qos: WirepasMeshQOS // e.g. 1
}
export type WirepasGateway = {
id: string
type: DeviceType.WIREPAS_5G_MESH_GW
location?: Record<GeoLocationSource, GeoLocation>
state: {
nodes: Record<string /* node id */, WirepasGatewayNode>
}
}

export type Devices = Record<string, Device>

export type Reading = [
Expand All @@ -203,6 +233,7 @@ export type Summary = {
}

export const isTracker = (device: Device): boolean => {
if (!('state' in device)) return false
const { appV, brdV } = device.state?.dev?.v ?? {}
return appV !== undefined && brdV !== undefined
}
Expand All @@ -220,6 +251,14 @@ export const isNRPlusGateway = (
typeof device.state === 'object' &&
'nodes' in (device.state ?? {})

export const isWirepasGateway = (
device: Record<string, unknown>,
): device is WirepasGateway =>
'id' in device &&
typeof device.id === 'string' &&
'type' in device &&
device.type === DeviceType.WIREPAS_5G_MESH_GW

export const DevicesContext = createContext<{
devices: Devices
updateState: (deviceId: string, reported: Reported) => void
Expand All @@ -230,21 +269,26 @@ export const DevicesContext = createContext<{
) => void
updateHistory: (deviceId: string, history: Summary) => void
updateAlias: (deviceId: string, alias: string) => void
updateType: (deviceId: string, type: DeviceType) => void
toggleHiddenLocation: (deviceId: string, location: GeoLocationSource) => void
lastUpdateTs: (deviceId: string) => number | null
alias: (deviceId: string) => string | undefined
type: (deviceId: string) => DeviceType | undefined
}>({
updateState: () => undefined,
updateLocation: () => undefined,
updateHistory: () => undefined,
updateAlias: () => undefined,
alias: () => undefined,
updateType: () => undefined,
type: () => undefined,
toggleHiddenLocation: () => undefined,
lastUpdateTs: () => null,
devices: {},
})

const deviceAliases: Record<string, string> = {}
const deviceTypes: Record<string, DeviceType> = {}

export const Provider = ({ children }: { children: ComponentChildren }) => {
const [knownDevices, updateDevices] = useState<Devices>({})
Expand Down Expand Up @@ -378,22 +422,30 @@ export const Provider = ({ children }: { children: ComponentChildren }) => {
lastUpdateTs: (deviceId) => {
const device = knownDevices[deviceId]
if (device === undefined) return null
return isNRPlusGateway(device)
? getLastUpdateTime(
Object.values(device.state.nodes)
.map((node) => [
node.pccStatus?.ts,
node.btn?.ts,
node.env?.ts,
])
.flat(),
)
: getDeviceLastUpdateTime(knownDevices[deviceId])
if (isNRPlusGateway(device))
return getLastUpdateTime(
Object.values(device.state.nodes)
.map((node) => [node.pccStatus?.ts, node.btn?.ts, node.env?.ts])
.flat(),
)
if (deviceTypes[device.id] === DeviceType.WIREPAS_5G_MESH_GW) {
const nodes = (device as WirepasGateway).state.nodes
return getLastUpdateTime(
Object.values(nodes).map((node) =>
new Date(node.rxTime).getTime(),
),
)
}
return getDeviceLastUpdateTime(knownDevices[deviceId])
},
updateAlias: (deviceId, alias) => {
deviceAliases[deviceId] = alias
},
alias: (deviceId) => deviceAliases[deviceId],
updateType: (deviceId, type) => {
deviceTypes[deviceId] = type
},
type: (deviceId) => deviceTypes[deviceId],
}}
>
{children}
Expand Down
2 changes: 2 additions & 0 deletions src/context/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useContext, useState } from 'preact/hooks'

type Settings = {
enableTestDevice: boolean
enableWirepas5GMeshGateways: boolean
showFavorites: boolean
showSettings: boolean
favorites: string[]
Expand All @@ -12,6 +13,7 @@ type Settings = {

const defaultSettings: Settings = {
enableTestDevice: false,
enableWirepas5GMeshGateways: false,
showFavorites: false,
showSettings: false,
favorites: [],
Expand Down
8 changes: 8 additions & 0 deletions src/context/WebsocketConnection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
type Reported,
type Summary,
GeoLocationSource,
DeviceType,
} from './Devices.js'

export const WebsocketContext = createContext<{
Expand Down Expand Up @@ -34,6 +35,7 @@ type Message = {
deviceAlias?: string
// Fixed location for the device
deviceLocation?: string // e.g. 63.42115901688979,10.437200141182338
deviceType?: string
} & (
| {
'@context': MessageContext.DeviceLocation
Expand Down Expand Up @@ -147,6 +149,12 @@ export const Provider = ({ children }: { children: ComponentChildren }) => {
'fixed',
)
}
if (message.deviceType !== undefined) {
deviceMessages.updateType(
message.deviceId,
message.deviceType as DeviceType,
)
}
listeners.current.map((fn) => fn(message))
})

Expand Down
52 changes: 52 additions & 0 deletions src/icons/5GMesh.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
export const FiveGMesh = ({ ...props }) => (
<svg
version="1.1"
x="0px"
y="0px"
viewBox="0 0 212.80001 212.8"
width="212.8"
height="212.8"
xmlns="http://www.w3.org/2000/svg"
{...props}
style={{ padding: '0.25rem' }}
>
<g transform="translate(0,7.4000015)">
<g transform="translate(-29.3,-27)">
<path
fill="#fbf2e8"
d="m 194.2,158.5 c -0.8,-12.3 2.1,-24.5 8.4,-35.5 L 242.1,54.6 194.3,27 154.8,95.4 c -13.7,23.7 -18.7,50.8 -14.5,77.5 z"
/>
<path
fill="#fbf2e8"
d="M 77.2,158.5 C 78,146.2 75.1,134 68.8,123 L 29.3,54.6 77.1,27 116.6,95.4 c 13.7,23.7 18.7,50.8 14.5,77.5 z"
/>
</g>
<g transform="translate(-29.3,-27)">
<path
fill="#fbf2e8"
d="m 33.5,216.1 6.9,-4.6 c 2.5,3.9 4,5.1 6.3,5.1 3,0 4.9,-2.2 4.9,-5.7 0,-3.7 -2.3,-5.8 -6.3,-5.8 -4.3,0 -7.2,2.4 -8.8,4.5 l 1.1,-21.3 h 21 v 8.2 H 46.3 v 2.4 c 0.4,0 0.8,0 1.1,0 7.6,0 13,4.9 13,12.5 0,7.5 -5.7,13.6 -13.7,13.6 -5.7,-0.3 -10.5,-3.4 -13.2,-8.9 z"
/>
<path
fill="#fbf2e8"
d="m 71.6,206.2 c 0,5.8 4.2,10.3 9.5,10.3 0.3,0 0.6,0 1.1,-0.1 v -6.3 h -5.9 v -8.3 H 91 v 20.4 c -2.5,1.7 -6.1,2.6 -9.8,2.6 -10.8,0 -19,-8 -19,-18.6 0,-10.5 7.9,-18.6 18.9,-18.6 4.4,0 8.2,1.3 10.9,3.8 v 9.7 c -1.3,-2.8 -4.9,-5.2 -9.4,-5.2 -6.2,0 -11,4.4 -11,10.3 z"
/>
<path
fill="#fbf2e8"
d="m 152.9,224.2 h -8.7 V 205 l -13.7,19.2 h -5.1 v -14.9 l -10.6,14.9 h -10.9 l 26,-36 h 4.2 v 16.5 l 11.7,-16.5 h 7.1 z"
/>
<path
fill="#fbf2e8"
d="M 164.5,202.2 H 184 v 7.9 h -19.4 c 1.6,3.8 5.5,6.4 10.1,6.4 4.5,0 8,-2.4 9.4,-5.2 v 9.7 c -2.7,2.4 -6.5,3.8 -10.9,3.8 -11,0 -18.9,-8 -18.9,-18.6 0,-10.5 7.9,-18.6 18.9,-18.6 4.4,0 8.2,1.3 10.9,3.8 v 9.7 c -1.3,-2.8 -4.9,-5.2 -9.4,-5.2 -4.7,0 -8.6,2.6 -10.2,6.3 z"
/>
<path
fill="#fbf2e8"
d="m 198.3,215.3 c -0.3,-6.3 -13,-9.2 -13,-17 0,-6 5,-10.7 11.4,-10.7 7.3,0 12.3,5.6 10.9,13 h -8.7 c 0.9,-4 -0.5,-5 -2.3,-5 -1.5,0 -2.4,1.1 -2.4,2.7 0,5.6 11.8,7.6 11.8,16 0,3.8 -2.6,8.2 -7,9.9 h -11.3 c 3.9,-2.7 10.6,-5.4 10.6,-8.9 z"
/>
<path
fill="#fbf2e8"
d="m 217.6,188.2 v 13.7 H 229 v -13.7 h 8.9 v 36 H 229 V 210 h -11.4 v 14.2 h -8.9 v -36 z"
/>
</g>
</g>
</svg>
)
Loading

0 comments on commit 916a5a0

Please sign in to comment.