Compare commits
3 Commits
d6c495be66
...
tuanta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8af31a0435 | ||
| 256ce06ea2 | |||
| acb453d98d |
@@ -52,7 +52,8 @@ export const handleRequestConfig: RequestConfig = {
|
|||||||
return (
|
return (
|
||||||
(status >= 200 && status < 300) ||
|
(status >= 200 && status < 300) ||
|
||||||
status === HTTPSTATUS.HTTP_NOTFOUND ||
|
status === HTTPSTATUS.HTTP_NOTFOUND ||
|
||||||
status === HTTPSTATUS.HTTP_UNAUTHORIZED
|
status === HTTPSTATUS.HTTP_UNAUTHORIZED ||
|
||||||
|
status === HTTPSTATUS.HTTP_FORBIDDEN
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
headers: { 'X-Requested-With': 'XMLHttpRequest' },
|
headers: { 'X-Requested-With': 'XMLHttpRequest' },
|
||||||
@@ -121,15 +122,16 @@ export const handleRequestConfig: RequestConfig = {
|
|||||||
// Unwrap data from backend response
|
// Unwrap data from backend response
|
||||||
responseInterceptors: [
|
responseInterceptors: [
|
||||||
async (response: any, options: any) => {
|
async (response: any, options: any) => {
|
||||||
const isRefreshRequest = response.url?.includes(API_PATH_REFRESH_TOKEN);
|
const isRefreshRequest = response.config.url?.includes(
|
||||||
const alreadyRetried = options?.skipAuthRefresh === true;
|
API_PATH_REFRESH_TOKEN,
|
||||||
|
);
|
||||||
|
console.log('Is refresh request:', isRefreshRequest);
|
||||||
|
|
||||||
// Xử lý 401: đưa request vào hàng đợi, gọi refresh token, rồi gọi lại
|
// Xử lý 401: đưa request vào hàng đợi, gọi refresh token, rồi gọi lại
|
||||||
if (
|
if (
|
||||||
response.status === HTTPSTATUS.HTTP_UNAUTHORIZED &&
|
response.status === HTTPSTATUS.HTTP_UNAUTHORIZED &&
|
||||||
// Không tự refresh cho chính API refresh token để tránh vòng lặp vô hạn
|
// Không tự refresh cho chính API refresh token để tránh vòng lặp vô hạn
|
||||||
!isRefreshRequest &&
|
!isRefreshRequest
|
||||||
!alreadyRetried
|
|
||||||
) {
|
) {
|
||||||
const newToken = await getValidAccessToken();
|
const newToken = await getValidAccessToken();
|
||||||
console.log('Access Token hết hạn, đang refresh...');
|
console.log('Access Token hết hạn, đang refresh...');
|
||||||
@@ -172,7 +174,7 @@ export const handleRequestConfig: RequestConfig = {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
response.status === HTTPSTATUS.HTTP_UNAUTHORIZED &&
|
response.status === HTTPSTATUS.HTTP_UNAUTHORIZED &&
|
||||||
(isRefreshRequest || alreadyRetried)
|
isRefreshRequest
|
||||||
) {
|
) {
|
||||||
clearAllData();
|
clearAllData();
|
||||||
history.push(ROUTE_LOGIN);
|
history.push(ROUTE_LOGIN);
|
||||||
|
|||||||
30
package-lock.json
generated
30
package-lock.json
generated
@@ -10,10 +10,12 @@
|
|||||||
"@ant-design/pro-components": "^2.8.10",
|
"@ant-design/pro-components": "^2.8.10",
|
||||||
"@umijs/max": "^4.6.23",
|
"@umijs/max": "^4.6.23",
|
||||||
"antd": "^5.4.0",
|
"antd": "^5.4.0",
|
||||||
|
"chart.js": "^4.5.1",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"ol": "^10.6.1",
|
"ol": "^10.6.1",
|
||||||
|
"react-chartjs-2": "^5.3.1",
|
||||||
"reconnecting-websocket": "^4.4.0"
|
"reconnecting-websocket": "^4.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -2842,6 +2844,12 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@kurkle/color": {
|
||||||
|
"version": "0.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
|
||||||
|
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@loadable/component": {
|
"node_modules/@loadable/component": {
|
||||||
"version": "5.15.2",
|
"version": "5.15.2",
|
||||||
"resolved": "https://registry.npmjs.org/@loadable/component/-/component-5.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/@loadable/component/-/component-5.15.2.tgz",
|
||||||
@@ -8422,6 +8430,18 @@
|
|||||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chart.js": {
|
||||||
|
"version": "4.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz",
|
||||||
|
"integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@kurkle/color": "^0.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"pnpm": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/chokidar": {
|
"node_modules/chokidar": {
|
||||||
"version": "3.5.3",
|
"version": "3.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||||
@@ -17295,6 +17315,16 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-chartjs-2": {
|
||||||
|
"version": "5.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.3.1.tgz",
|
||||||
|
"integrity": "sha512-h5IPXKg9EXpjoBzUfyWJvllMjG2mQ4EiuHQFhms/AjUm0XSZHhyRy2xVmLXHKrtcdrPO4mnGqRtYoD0vp95A0A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"chart.js": "^4.1.1",
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "18.3.1",
|
"version": "18.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||||
|
|||||||
@@ -21,10 +21,12 @@
|
|||||||
"@ant-design/pro-components": "^2.8.10",
|
"@ant-design/pro-components": "^2.8.10",
|
||||||
"@umijs/max": "^4.6.23",
|
"@umijs/max": "^4.6.23",
|
||||||
"antd": "^5.4.0",
|
"antd": "^5.4.0",
|
||||||
|
"chart.js": "^4.5.1",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"ol": "^10.6.1",
|
"ol": "^10.6.1",
|
||||||
|
"react-chartjs-2": "^5.3.1",
|
||||||
"reconnecting-websocket": "^4.4.0"
|
"reconnecting-websocket": "^4.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
30
pnpm-lock.yaml
generated
30
pnpm-lock.yaml
generated
@@ -20,6 +20,9 @@ importers:
|
|||||||
antd:
|
antd:
|
||||||
specifier: ^5.4.0
|
specifier: ^5.4.0
|
||||||
version: 5.29.3(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 5.29.3(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
chart.js:
|
||||||
|
specifier: ^4.5.1
|
||||||
|
version: 4.5.1
|
||||||
classnames:
|
classnames:
|
||||||
specifier: ^2.5.1
|
specifier: ^2.5.1
|
||||||
version: 2.5.1
|
version: 2.5.1
|
||||||
@@ -32,6 +35,9 @@ importers:
|
|||||||
ol:
|
ol:
|
||||||
specifier: ^10.6.1
|
specifier: ^10.6.1
|
||||||
version: 10.7.0
|
version: 10.7.0
|
||||||
|
react-chartjs-2:
|
||||||
|
specifier: ^5.3.1
|
||||||
|
version: 5.3.1(chart.js@4.5.1)(react@18.3.1)
|
||||||
reconnecting-websocket:
|
reconnecting-websocket:
|
||||||
specifier: ^4.4.0
|
specifier: ^4.4.0
|
||||||
version: 4.4.0
|
version: 4.4.0
|
||||||
@@ -958,6 +964,9 @@ packages:
|
|||||||
'@jridgewell/trace-mapping@0.3.31':
|
'@jridgewell/trace-mapping@0.3.31':
|
||||||
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==, tarball: https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz}
|
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==, tarball: https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz}
|
||||||
|
|
||||||
|
'@kurkle/color@0.3.4':
|
||||||
|
resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==, tarball: https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz}
|
||||||
|
|
||||||
'@loadable/component@5.15.2':
|
'@loadable/component@5.15.2':
|
||||||
resolution: {integrity: sha512-ryFAZOX5P2vFkUdzaAtTG88IGnr9qxSdvLRvJySXcUA4B4xVWurUNADu3AnKPksxOZajljqTrDEDcYjeL4lvLw==, tarball: https://registry.npmjs.org/@loadable/component/-/component-5.15.2.tgz}
|
resolution: {integrity: sha512-ryFAZOX5P2vFkUdzaAtTG88IGnr9qxSdvLRvJySXcUA4B4xVWurUNADu3AnKPksxOZajljqTrDEDcYjeL4lvLw==, tarball: https://registry.npmjs.org/@loadable/component/-/component-5.15.2.tgz}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -2215,6 +2224,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==, tarball: https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz}
|
resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==, tarball: https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz}
|
||||||
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
|
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
|
||||||
|
|
||||||
|
chart.js@4.5.1:
|
||||||
|
resolution: {integrity: sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==, tarball: https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz}
|
||||||
|
engines: {pnpm: '>=8'}
|
||||||
|
|
||||||
chokidar@3.5.3:
|
chokidar@3.5.3:
|
||||||
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==, tarball: https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz}
|
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==, tarball: https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz}
|
||||||
engines: {node: '>= 8.10.0'}
|
engines: {node: '>= 8.10.0'}
|
||||||
@@ -5382,6 +5395,12 @@ packages:
|
|||||||
react: '>=16.9.0'
|
react: '>=16.9.0'
|
||||||
react-dom: '>=16.9.0'
|
react-dom: '>=16.9.0'
|
||||||
|
|
||||||
|
react-chartjs-2@5.3.1:
|
||||||
|
resolution: {integrity: sha512-h5IPXKg9EXpjoBzUfyWJvllMjG2mQ4EiuHQFhms/AjUm0XSZHhyRy2xVmLXHKrtcdrPO4mnGqRtYoD0vp95A0A==, tarball: https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.3.1.tgz}
|
||||||
|
peerDependencies:
|
||||||
|
chart.js: ^4.1.1
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
react-dom@18.3.1:
|
react-dom@18.3.1:
|
||||||
resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==, tarball: https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz}
|
resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==, tarball: https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -7759,6 +7778,8 @@ snapshots:
|
|||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
|
'@kurkle/color@0.3.4': {}
|
||||||
|
|
||||||
'@loadable/component@5.15.2(react@18.3.1)':
|
'@loadable/component@5.15.2(react@18.3.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.23.6
|
'@babel/runtime': 7.23.6
|
||||||
@@ -9573,6 +9594,10 @@ snapshots:
|
|||||||
|
|
||||||
chalk@5.3.0: {}
|
chalk@5.3.0: {}
|
||||||
|
|
||||||
|
chart.js@4.5.1:
|
||||||
|
dependencies:
|
||||||
|
'@kurkle/color': 0.3.4
|
||||||
|
|
||||||
chokidar@3.5.3:
|
chokidar@3.5.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
anymatch: 3.1.3
|
anymatch: 3.1.3
|
||||||
@@ -13208,6 +13233,11 @@ snapshots:
|
|||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
react-dom: 18.3.1(react@18.3.1)
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
|
||||||
|
react-chartjs-2@5.3.1(chart.js@4.5.1)(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
chart.js: 4.5.1
|
||||||
|
react: 18.3.1
|
||||||
|
|
||||||
react-dom@18.3.1(react@18.3.1):
|
react-dom@18.3.1(react@18.3.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
loose-envify: 1.4.0
|
loose-envify: 1.4.0
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState }) => {
|
|||||||
contentWidth: 'Fluid',
|
contentWidth: 'Fluid',
|
||||||
navTheme: isDark ? 'realDark' : 'light',
|
navTheme: isDark ? 'realDark' : 'light',
|
||||||
splitMenus: true,
|
splitMenus: true,
|
||||||
iconfontUrl: '//at.alicdn.com/t/c/font_5096559_rzr2z3xtksr.js',
|
iconfontUrl: '//at.alicdn.com/t/c/font_5096559_0wzlbggptqk.js',
|
||||||
contentStyle: {
|
contentStyle: {
|
||||||
padding: 0,
|
padding: 0,
|
||||||
margin: 0,
|
margin: 0,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createFromIconfontCN } from '@ant-design/icons';
|
import { createFromIconfontCN } from '@ant-design/icons';
|
||||||
|
|
||||||
const IconFont = createFromIconfontCN({
|
const IconFont = createFromIconfontCN({
|
||||||
scriptUrl: '//at.alicdn.com/t/c/font_5096559_rzr2z3xtksr.js',
|
scriptUrl: '//at.alicdn.com/t/c/font_5096559_0wzlbggptqk.js',
|
||||||
});
|
});
|
||||||
|
|
||||||
export default IconFont;
|
export default IconFont;
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
import IconFont from '@/components/IconFont';
|
import IconFont from '@/components/IconFont';
|
||||||
import { StatisticCard } from '@ant-design/pro-components';
|
import { StatisticCard } from '@ant-design/pro-components';
|
||||||
import {
|
import { Flex, GlobalToken, Grid, theme, Tooltip, Typography } from 'antd';
|
||||||
Divider,
|
|
||||||
Flex,
|
|
||||||
GlobalToken,
|
|
||||||
Grid,
|
|
||||||
theme,
|
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
} from 'antd';
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
type BinarySensorsProps = {
|
type BinarySensorsProps = {
|
||||||
nodeConfigs: MasterModel.NodeConfig[];
|
nodeConfigs: MasterModel.NodeConfig[];
|
||||||
@@ -148,7 +140,6 @@ const BinarySensors = ({ nodeConfigs }: BinarySensorsProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex wrap="wrap" gap="middle">
|
<Flex wrap="wrap" gap="middle">
|
||||||
<Divider orientation="left">Cảm biến</Divider>
|
|
||||||
{binarySensors.map((entity) => (
|
{binarySensors.map((entity) => (
|
||||||
<div
|
<div
|
||||||
key={entity.entityId}
|
key={entity.entityId}
|
||||||
|
|||||||
610
src/pages/Manager/Device/Detail/components/Chart.tsx
Normal file
610
src/pages/Manager/Device/Detail/components/Chart.tsx
Normal file
@@ -0,0 +1,610 @@
|
|||||||
|
import '@/utils/chart';
|
||||||
|
import type { ChartData, ChartOptions } from 'chart.js';
|
||||||
|
import { Line } from 'react-chartjs-2';
|
||||||
|
|
||||||
|
type ChartComponentProps = {
|
||||||
|
message: MasterModel.SensorLogMessage[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const exampleSensorLogMessages: MasterModel.SensorLogMessage[] = [
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770260026,
|
||||||
|
value: 76.3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770259725,
|
||||||
|
value: 77.1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770259424,
|
||||||
|
value: 75.6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770259242,
|
||||||
|
value: 72.6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770259142,
|
||||||
|
value: 69.6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770258926,
|
||||||
|
value: 66.6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770258877,
|
||||||
|
value: 69.6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770258839,
|
||||||
|
value: 73,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770258678,
|
||||||
|
value: 76.1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770258377,
|
||||||
|
value: 77.6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770258077,
|
||||||
|
value: 77.8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770257776,
|
||||||
|
value: 75.6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770257596,
|
||||||
|
value: 72.5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770257487,
|
||||||
|
value: 69.5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770257412,
|
||||||
|
value: 66.4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770257349,
|
||||||
|
value: 63.3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770257117,
|
||||||
|
value: 60.3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770256816,
|
||||||
|
value: 62.3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770256625,
|
||||||
|
value: 65.3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770256563,
|
||||||
|
value: 68.4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770256529,
|
||||||
|
value: 71.4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770256363,
|
||||||
|
value: 74.7,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770256062,
|
||||||
|
value: 75.2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770255761,
|
||||||
|
value: 74.3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770255590,
|
||||||
|
value: 71.2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770255498,
|
||||||
|
value: 68.1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770255436,
|
||||||
|
value: 64.9,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770255331,
|
||||||
|
value: 61.8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770255111,
|
||||||
|
value: 64.8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770255038,
|
||||||
|
value: 67.9,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770255002,
|
||||||
|
value: 71.1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770254968,
|
||||||
|
value: 74.2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770254688,
|
||||||
|
value: 77.4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770254387,
|
||||||
|
value: 78.4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770254086,
|
||||||
|
value: 77.9,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770253786,
|
||||||
|
value: 75,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770253631,
|
||||||
|
value: 72,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770253549,
|
||||||
|
value: 68.9,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770253481,
|
||||||
|
value: 65.8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770253434,
|
||||||
|
value: 62.7,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770253364,
|
||||||
|
value: 59.6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770253063,
|
||||||
|
value: 60.4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770252763,
|
||||||
|
value: 62.5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770252695,
|
||||||
|
value: 65.5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770252657,
|
||||||
|
value: 68.6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770252489,
|
||||||
|
value: 71.7,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770252188,
|
||||||
|
value: 71.2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770251886,
|
||||||
|
value: 68.7,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770251585,
|
||||||
|
value: 65.9,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channel: 'c2552f8e-6e2f-4703-bdc2-681d2a0646d9',
|
||||||
|
subtopic: 'log.gmsv5.hum.0:20',
|
||||||
|
publisher: 'f4bd927c-f578-420d-9b63-ef7fb053d901',
|
||||||
|
protocol: 'mqtt',
|
||||||
|
name: 'urn:dev:mac:0038310555e4:0:20',
|
||||||
|
unit: '%',
|
||||||
|
time: 1770251469,
|
||||||
|
value: 68.9,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// Custom plugin để vẽ đường kẻ dọc khi hover
|
||||||
|
const verticalLinePlugin = {
|
||||||
|
id: 'verticalLine',
|
||||||
|
afterDraw: (chart: any) => {
|
||||||
|
if (chart.tooltip?._active?.length) {
|
||||||
|
const ctx = chart.ctx;
|
||||||
|
const x = chart.tooltip._active[0].element.x;
|
||||||
|
const topY = chart.scales.y.top;
|
||||||
|
const bottomY = chart.scales.y.bottom;
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x, topY);
|
||||||
|
ctx.lineTo(x, bottomY);
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.strokeStyle = 'rgba(0, 0, 0, 0.3)';
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const ChartComponent = () => {
|
||||||
|
const data: ChartData<'line', number[], string> = {
|
||||||
|
labels: exampleSensorLogMessages.map((msg) =>
|
||||||
|
new Date(msg.time! * 1000).toLocaleTimeString(),
|
||||||
|
),
|
||||||
|
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: exampleSensorLogMessages[0]?.unit || '',
|
||||||
|
data: exampleSensorLogMessages.map((msg) => msg.value),
|
||||||
|
borderColor: 'rgba(75, 192, 192, 0.2)',
|
||||||
|
backgroundColor: 'rgba(75, 192, 192, 0.2)',
|
||||||
|
tension: 0.1,
|
||||||
|
fill: 'start',
|
||||||
|
pointRadius: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const options: ChartOptions<'line'> = {
|
||||||
|
interaction: {
|
||||||
|
mode: 'index',
|
||||||
|
intersect: true,
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
ticks: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
display: false,
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
tooltip: {
|
||||||
|
enabled: true,
|
||||||
|
mode: 'index',
|
||||||
|
intersect: false,
|
||||||
|
callbacks: {
|
||||||
|
label: (context) => {
|
||||||
|
return `${context.parsed.y} ${
|
||||||
|
exampleSensorLogMessages[0]?.unit || ''
|
||||||
|
}`;
|
||||||
|
},
|
||||||
|
title: (context) => {
|
||||||
|
const index = context[0]?.dataIndex;
|
||||||
|
if (index !== undefined) {
|
||||||
|
const msg = exampleSensorLogMessages[index];
|
||||||
|
return new Date(msg.time! * 1000).toLocaleString();
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Line
|
||||||
|
title="Nooo"
|
||||||
|
data={data}
|
||||||
|
options={options}
|
||||||
|
plugins={[verticalLinePlugin]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChartComponent;
|
||||||
@@ -3,11 +3,17 @@ import TooltipIconFontButton from '@/components/shared/TooltipIconFontButton';
|
|||||||
import { ROUTER_HOME } from '@/constants/routes';
|
import { ROUTER_HOME } from '@/constants/routes';
|
||||||
import { apiQueryNodeConfigMessage } from '@/services/master/MessageController';
|
import { apiQueryNodeConfigMessage } from '@/services/master/MessageController';
|
||||||
import { apiGetThingDetail } from '@/services/master/ThingController';
|
import { apiGetThingDetail } from '@/services/master/ThingController';
|
||||||
|
import {
|
||||||
|
EditOutlined,
|
||||||
|
EllipsisOutlined,
|
||||||
|
SettingOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
import { PageContainer, ProCard } from '@ant-design/pro-components';
|
import { PageContainer, ProCard } from '@ant-design/pro-components';
|
||||||
import { history, useIntl, useModel, useParams } from '@umijs/max';
|
import { history, useIntl, useModel, useParams } from '@umijs/max';
|
||||||
import { Divider, Flex, Grid } from 'antd';
|
import { Divider, Flex, Grid } from 'antd';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import BinarySensors from './components/BinarySensors';
|
import BinarySensors from './components/BinarySensors';
|
||||||
|
import ChartComponent from './components/Chart';
|
||||||
import ThingTitle from './components/ThingTitle';
|
import ThingTitle from './components/ThingTitle';
|
||||||
|
|
||||||
const DetailDevicePage = () => {
|
const DetailDevicePage = () => {
|
||||||
@@ -109,8 +115,21 @@ const DetailDevicePage = () => {
|
|||||||
</ProCard>
|
</ProCard>
|
||||||
<ProCard colSpan={{ xs: 24, sm: 24, md: 24, lg: 18, xl: 18 }}>
|
<ProCard colSpan={{ xs: 24, sm: 24, md: 24, lg: 18, xl: 18 }}>
|
||||||
<Flex wrap gap="small">
|
<Flex wrap gap="small">
|
||||||
|
<Divider orientation="left">Cảm biến</Divider>
|
||||||
<BinarySensors nodeConfigs={nodeConfigs} />
|
<BinarySensors nodeConfigs={nodeConfigs} />
|
||||||
<Divider orientation="left">Trạng thái</Divider>
|
<Divider orientation="left">Trạng thái</Divider>
|
||||||
|
<ProCard
|
||||||
|
title="Mẫu 1"
|
||||||
|
bordered
|
||||||
|
style={{ maxWidth: 600 }}
|
||||||
|
actions={[
|
||||||
|
<SettingOutlined key="setting" />,
|
||||||
|
<EditOutlined key="edit" />,
|
||||||
|
<EllipsisOutlined key="ellipsis" />,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<ChartComponent />
|
||||||
|
</ProCard>
|
||||||
</Flex>
|
</Flex>
|
||||||
</ProCard>
|
</ProCard>
|
||||||
</ProCard>
|
</ProCard>
|
||||||
|
|||||||
@@ -165,7 +165,6 @@ const ManagerDevicePage = () => {
|
|||||||
'-'
|
'-'
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
key: 'type',
|
key: 'type',
|
||||||
hideInSearch: true,
|
hideInSearch: true,
|
||||||
|
|||||||
@@ -211,3 +211,19 @@ export async function apiQueryConfigAlarm(
|
|||||||
|
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function apiQuerySensorLogMessage(
|
||||||
|
dataChanelId: string,
|
||||||
|
authorization: string,
|
||||||
|
params: MasterModel.SearchMessagePaginationBody,
|
||||||
|
) {
|
||||||
|
return request<
|
||||||
|
MasterModel.MesageReaderResponse<MasterModel.SensorLogMessage[]>
|
||||||
|
>(`${API_READER}/${dataChanelId}/messages`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
Authorization: authorization,
|
||||||
|
},
|
||||||
|
params: params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
22
src/services/master/typings/log.d.ts
vendored
22
src/services/master/typings/log.d.ts
vendored
@@ -6,6 +6,15 @@ declare namespace MasterModel {
|
|||||||
subtopic?: string;
|
subtopic?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface MessageBasicInfo {
|
||||||
|
channel?: string;
|
||||||
|
subtopic?: string;
|
||||||
|
publisher?: string;
|
||||||
|
protocol?: string;
|
||||||
|
name?: string;
|
||||||
|
time?: number;
|
||||||
|
}
|
||||||
|
|
||||||
type LogTypeRequest = 'user_logs' | undefined;
|
type LogTypeRequest = 'user_logs' | undefined;
|
||||||
|
|
||||||
interface MesageReaderResponse<T = MessageDataType> {
|
interface MesageReaderResponse<T = MessageDataType> {
|
||||||
@@ -27,13 +36,7 @@ declare namespace MasterModel {
|
|||||||
|
|
||||||
type MessageDataType = NodeConfig[] | CameraV5 | CameraV6;
|
type MessageDataType = NodeConfig[] | CameraV5 | CameraV6;
|
||||||
|
|
||||||
interface Message<T = MessageDataType> {
|
interface Message<T = MessageDataType> extends MessageBasicInfo {
|
||||||
channel?: string;
|
|
||||||
subtopic?: string;
|
|
||||||
publisher?: string;
|
|
||||||
protocol?: string;
|
|
||||||
name?: string;
|
|
||||||
time?: number;
|
|
||||||
string_value?: string;
|
string_value?: string;
|
||||||
string_value_parsed?: T;
|
string_value_parsed?: T;
|
||||||
}
|
}
|
||||||
@@ -69,4 +72,9 @@ declare namespace MasterModel {
|
|||||||
type: Type;
|
type: Type;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SensorLogMessage extends MessageBasicInfo {
|
||||||
|
unit: string;
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
src/utils/chart.ts
Normal file
22
src/utils/chart.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import {
|
||||||
|
BarElement,
|
||||||
|
CategoryScale,
|
||||||
|
Chart as ChartJS,
|
||||||
|
Filler,
|
||||||
|
Legend,
|
||||||
|
LinearScale,
|
||||||
|
LineElement,
|
||||||
|
PointElement,
|
||||||
|
Tooltip,
|
||||||
|
} from 'chart.js';
|
||||||
|
|
||||||
|
ChartJS.register(
|
||||||
|
CategoryScale,
|
||||||
|
LinearScale,
|
||||||
|
PointElement,
|
||||||
|
LineElement,
|
||||||
|
BarElement,
|
||||||
|
Filler,
|
||||||
|
Tooltip,
|
||||||
|
Legend,
|
||||||
|
);
|
||||||
118
update-iconfont.sh
Normal file
118
update-iconfont.sh
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "=== Update Iconfont - Git Push Script with Merge Main ==="
|
||||||
|
|
||||||
|
# Hàm kiểm tra lỗi và thoát
|
||||||
|
handle_error() {
|
||||||
|
echo "❌ Lỗi: $1"
|
||||||
|
# Nếu có stash, hiển thị thông báo để người dùng biết cách xử lý
|
||||||
|
if [ "$stashed" = true ]; then
|
||||||
|
echo "⚠️ Có stash được lưu, hãy kiểm tra bằng 'git stash list' và xử lý thủ công nếu cần."
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Kiểm tra xem có trong Git repository không
|
||||||
|
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||||
|
handle_error "Thư mục hiện tại không phải là Git repository!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Các file cần commit
|
||||||
|
FILE1="src/components/IconFont/index.tsx"
|
||||||
|
FILE2="src/app.tsx"
|
||||||
|
|
||||||
|
# Kiểm tra file tồn tại
|
||||||
|
if [ ! -f "$FILE1" ]; then
|
||||||
|
handle_error "Không tìm thấy file $FILE1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$FILE2" ]; then
|
||||||
|
handle_error "Không tìm thấy file $FILE2"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Lấy nhánh hiện tại
|
||||||
|
current_branch=$(git branch --show-current)
|
||||||
|
if [ -z "$current_branch" ]; then
|
||||||
|
handle_error "Không thể xác định nhánh hiện tại!"
|
||||||
|
fi
|
||||||
|
echo "👉 Bạn đang ở nhánh: $current_branch"
|
||||||
|
|
||||||
|
# Hỏi nhánh chính, mặc định là 'master' nếu người dùng không nhập
|
||||||
|
read -p "Nhập tên nhánh chính (mặc định: master): " target_branch
|
||||||
|
target_branch=${target_branch:-master}
|
||||||
|
|
||||||
|
# Kiểm tra xem nhánh chính có tồn tại trên remote không
|
||||||
|
if ! git ls-remote --heads origin "$target_branch" >/dev/null 2>&1; then
|
||||||
|
handle_error "Nhánh $target_branch không tồn tại trên remote!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Hiển thị thay đổi của 2 file
|
||||||
|
echo ""
|
||||||
|
echo "📋 Các thay đổi trong 2 file iconfont:"
|
||||||
|
echo "---"
|
||||||
|
git --no-pager diff "$FILE1" "$FILE2" 2>/dev/null || echo "(Không có thay đổi hoặc file chưa được track)"
|
||||||
|
echo "---"
|
||||||
|
|
||||||
|
# Kiểm tra có thay đổi không
|
||||||
|
if git diff --quiet "$FILE1" "$FILE2" 2>/dev/null && git diff --cached --quiet "$FILE1" "$FILE2" 2>/dev/null; then
|
||||||
|
echo "⚠️ Không có thay đổi nào trong 2 file iconfont."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Bước 1: Stash nếu có thay đổi chưa commit ---
|
||||||
|
stashed=false
|
||||||
|
if [[ -n $(git status --porcelain) ]]; then
|
||||||
|
echo "💾 Có thay đổi chưa commit -> stash lại..."
|
||||||
|
git stash push -m "auto-stash-before-iconfont-$(date +%s)" || handle_error "Lỗi khi stash code!"
|
||||||
|
stashed=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Bước 2: Đồng bộ code từ nhánh chính về nhánh hiện tại ---
|
||||||
|
echo "🔄 Đồng bộ code từ $target_branch về $current_branch..."
|
||||||
|
git fetch origin "$target_branch" || handle_error "Lỗi khi fetch $target_branch!"
|
||||||
|
git merge origin/"$target_branch" --no-edit || {
|
||||||
|
handle_error "Merge từ $target_branch về $current_branch bị conflict, hãy xử lý thủ công rồi chạy lại."
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Bước 3: Nếu có stash thì pop lại ---
|
||||||
|
if [ "$stashed" = true ]; then
|
||||||
|
echo "📥 Pop lại code đã stash..."
|
||||||
|
git stash pop || handle_error "Stash pop bị conflict, hãy xử lý thủ công bằng 'git stash list' và 'git stash apply'!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Bước 4: Add và Commit 2 file iconfont ---
|
||||||
|
echo "📥 Đang add 2 file iconfont..."
|
||||||
|
git add "$FILE1" "$FILE2" || handle_error "Lỗi khi add files!"
|
||||||
|
|
||||||
|
read -p "Nhập commit message (mặc định: 'chore: update iconfont url'): " commit_message
|
||||||
|
commit_message=${commit_message:-"chore: update iconfont url"}
|
||||||
|
git commit -m "$commit_message" || handle_error "Lỗi khi commit!"
|
||||||
|
|
||||||
|
# --- Bước 5: Push nhánh hiện tại ---
|
||||||
|
echo "🚀 Đang push nhánh $current_branch lên remote..."
|
||||||
|
git push origin "$current_branch" || handle_error "Push nhánh $current_branch thất bại!"
|
||||||
|
|
||||||
|
# --- Bước 6: Checkout sang nhánh chính ---
|
||||||
|
echo "🔄 Chuyển sang nhánh $target_branch..."
|
||||||
|
git checkout "$target_branch" || handle_error "Checkout sang $target_branch thất bại!"
|
||||||
|
|
||||||
|
# --- Bước 7: Pull nhánh chính ---
|
||||||
|
echo "🔄 Pull code mới nhất từ remote $target_branch..."
|
||||||
|
git pull origin "$target_branch" --no-rebase || handle_error "Pull $target_branch thất bại!"
|
||||||
|
|
||||||
|
# --- Bước 8: Merge nhánh hiện tại vào nhánh chính ---
|
||||||
|
echo "🔀 Merge $current_branch vào $target_branch..."
|
||||||
|
git merge "$current_branch" --no-edit || {
|
||||||
|
handle_error "Merge từ $current_branch vào $target_branch bị conflict, hãy xử lý thủ công rồi chạy lại."
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Bước 9: Push nhánh chính ---
|
||||||
|
git push origin "$target_branch" || handle_error "Push $target_branch thất bại!"
|
||||||
|
|
||||||
|
# --- Quay lại nhánh hiện tại ---
|
||||||
|
echo "🔄 Quay lại nhánh $current_branch..."
|
||||||
|
git checkout "$current_branch" || handle_error "Checkout về $current_branch thất bại!"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Hoàn tất! Đã commit 2 file iconfont và merge vào $target_branch."
|
||||||
Reference in New Issue
Block a user