-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add new pages for editing digital twin and preview data from altruist
- Loading branch information
Showing
18 changed files
with
1,007 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<template> | ||
<div v-if="isLaoded"> | ||
<datalog-chart :log="log" /> | ||
<robo-button @click="showRaw">Raw</robo-button> | ||
<datalog-list v-if="isShowRaw" :log="log" /> | ||
</div> | ||
<datalog-loader v-else /> | ||
</template> | ||
|
||
<script> | ||
import { ref, toRefs } from "vue"; | ||
import { useDatalog } from "./datalog"; | ||
import DatalogChart from "./DatalogChart.vue"; | ||
import DatalogList from "./DatalogList.vue"; | ||
import DatalogLoader from "./DatalogLoader.vue"; | ||
export default { | ||
props: ["address"], | ||
components: { DatalogList, DatalogLoader, DatalogChart }, | ||
setup(props) { | ||
const datalog = useDatalog(toRefs(props).address); | ||
const isShowRaw = ref(false); | ||
const showRaw = () => { | ||
isShowRaw.value = !isShowRaw.value; | ||
}; | ||
return { | ||
log: datalog.log, | ||
isLaoded: datalog.isLaoded, | ||
isShowRaw, | ||
showRaw | ||
}; | ||
} | ||
}; | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<template> | ||
<chart :options="chartOptions" ref="chart" /> | ||
</template> | ||
|
||
<script> | ||
import { Chart } from "highcharts-vue"; | ||
import { getCurrentInstance, onMounted, watch } from "vue"; | ||
export default { | ||
components: { Chart }, | ||
props: ["log"], | ||
setup(props) { | ||
const getSeries = (data) => { | ||
const seriesRaw = {}; | ||
for (const row of data) { | ||
for (const item of row.data) { | ||
if (seriesRaw[item.name]) { | ||
seriesRaw[item.name].data.push([ | ||
row.moment, | ||
parseFloat(item.value) | ||
]); | ||
} else { | ||
seriesRaw[item.name] = { | ||
name: item.name, | ||
data: [[row.moment, parseFloat(item.value)]] | ||
}; | ||
} | ||
} | ||
} | ||
return Object.values(seriesRaw); | ||
}; | ||
const series = getSeries(props.log); | ||
let chart; | ||
onMounted(() => { | ||
chart = getCurrentInstance().refs.chart.chart; | ||
}); | ||
watch(props.log, (value) => { | ||
if (!chart) { | ||
return; | ||
} | ||
const series = getSeries(value); | ||
if (series.length > 0) { | ||
series.forEach((newdata) => { | ||
const id = chart.series.findIndex((m) => m.name === newdata.name); | ||
if (id >= 0) { | ||
chart.series[id].setData(newdata.data, false); | ||
} else { | ||
chart.addSeries(newdata); | ||
} | ||
}); | ||
chart.redraw(); | ||
} | ||
}); | ||
return { | ||
chartOptions: { | ||
lang: { | ||
locale: "en" | ||
}, | ||
title: { | ||
text: "" | ||
}, | ||
time: { | ||
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone | ||
}, | ||
xAxis: { | ||
title: false, | ||
type: "datetime", | ||
labels: { | ||
overflow: "justify", | ||
format: "{value: %H:%M }" | ||
} | ||
}, | ||
yAxis: { | ||
title: false | ||
}, | ||
tooltip: { | ||
valueDecimals: 2 | ||
}, | ||
series: series | ||
} | ||
}; | ||
} | ||
}; | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<template> | ||
<div class="datalog-list"> | ||
<div | ||
class="datalog-item" | ||
v-for="(item, key) in log.slice().reverse()" | ||
:key="key" | ||
> | ||
<span class="time">{{ new Date(item.moment).toLocaleTimeString() }}</span> | ||
<code>{{ item.raw }}</code> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script> | ||
export default { | ||
props: ["log", "isLaoded"] | ||
}; | ||
</script> | ||
|
||
<style scoped> | ||
.datalog-list { | ||
overflow-y: scroll; | ||
height: 500px; | ||
border: 1px solid var(--robo-color-text); | ||
padding: 10px; | ||
background-color: #fff; | ||
} | ||
.datalog-item { | ||
padding: 5px; | ||
margin: 5px; | ||
border-bottom: 1px solid var(--robo-color-text); | ||
} | ||
.time { | ||
font-size: 12px; | ||
display: block; | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<template> | ||
<robo-text weight="normal-italic" align="center"> | ||
<robo-loader size="1.5" /> Loading | ||
</robo-text> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<template> | ||
<robo-layout-section> | ||
<robo-section offset="x2" width="narrow" style="text-align: center"> | ||
<h2>Altruist</h2> | ||
</robo-section> | ||
|
||
<robo-section offset="x2" width="narrow"> | ||
<datalog-loader v-if="isFind" /> | ||
<robo-status v-else-if="altruistAddress === null" type="warning"> | ||
Not found | ||
</robo-status> | ||
<altruist-chart | ||
v-else-if="altruistAddress !== undefined" | ||
:address="altruistAddress" | ||
/> | ||
</robo-section> | ||
</robo-layout-section> | ||
</template> | ||
|
||
<script> | ||
import { watch } from "vue"; | ||
import AltruistChart from "./AltruistChart.vue"; | ||
import DatalogLoader from "./DatalogLoader.vue"; | ||
import { useFindAltruist } from "./dtwin.js"; | ||
export default { | ||
props: ["address"], | ||
components: { AltruistChart, DatalogLoader }, | ||
setup(props) { | ||
const { address: altruistAddress, isFind, runFind } = useFindAltruist(); | ||
watch( | ||
() => props.address, | ||
(address) => { | ||
if (address) { | ||
altruistAddress.value = address; | ||
} else { | ||
runFind(); | ||
} | ||
}, | ||
{ immediate: true } | ||
); | ||
return { | ||
altruistAddress, | ||
isFind | ||
}; | ||
} | ||
}; | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import { useRobonomics } from "@/hooks/useRobonomics"; | ||
import { onUnmounted, ref, watch } from "vue"; | ||
|
||
const mapName = new Map([ | ||
["p1", "PM10"], | ||
["p2", "PM2.5"], | ||
["nm", "Noise Max."], | ||
["na", "Noise Avg."], | ||
["t", "Temperature"], | ||
["p", "Pressure"], | ||
["h", "Humidity"] | ||
]); | ||
|
||
/** | ||
* Given a key, return the corresponding name if the key exists in the map. | ||
* Otherwise, return the key itself. | ||
* | ||
* @param {string} key | ||
* @return {string} | ||
*/ | ||
const getName = (key) => { | ||
const name = mapName.get(key); | ||
if (name) { | ||
return name; | ||
} | ||
return key; | ||
}; | ||
|
||
/** | ||
* Parses a comma-separated string of key-value pairs into an array of objects. | ||
* Each object contains the original key, its mapped name from the mapName if available, | ||
* and the corresponding value. | ||
* | ||
* @param {string} data - A string containing key-value pairs separated by commas, | ||
* where each pair is separated by a colon. | ||
* @return {Array<{key: string, name: string, value: string}>} - An array of objects | ||
* with parsed key, name, and value. | ||
*/ | ||
const parseData = (data) => { | ||
return data.split(",").map((item) => { | ||
const [key, value] = item.split(":"); | ||
return { | ||
key, | ||
name: getName(key), | ||
value | ||
}; | ||
}); | ||
}; | ||
|
||
/** | ||
* Hook to read and subscribe to Robonomics datalog events from a given address. | ||
* | ||
* @param {string} address - The Robonomics address to read. | ||
* @return {{log: Ref<Array<{moment: number, data: Array<{key: string, name: string, value: string}>, raw: string}>}, isLaoded: Ref<boolean>}} | ||
* A reactive object containing the log and a boolean indicating if the log is loaded. | ||
*/ | ||
export const useDatalog = (address) => { | ||
const { isReady, getInstance } = useRobonomics(); | ||
|
||
const isLaoded = ref(false); | ||
const log = ref([]); | ||
let unsubscribe; | ||
|
||
const read = async (address) => { | ||
const robonomics = getInstance(); | ||
const data = await robonomics.datalog.read(address); | ||
return data.map((item) => { | ||
return { | ||
moment: item[0].toNumber(), | ||
data: parseData(item[1].toHuman()), | ||
raw: item[1].toHuman() | ||
}; | ||
}); | ||
}; | ||
|
||
const listener = async (address) => { | ||
const robonomics = getInstance(); | ||
unsubscribe = await robonomics.datalog.on({}, (result) => { | ||
for (const item of result) { | ||
if (item.data[0].toHuman() === address) { | ||
log.value.push({ | ||
moment: item.data[1].toNumber(), | ||
data: parseData(item.data[2].toHuman()), | ||
raw: item.data[2].toHuman() | ||
}); | ||
} | ||
} | ||
}); | ||
}; | ||
|
||
onUnmounted(() => { | ||
if (unsubscribe) { | ||
unsubscribe(); | ||
} | ||
}); | ||
|
||
watch( | ||
[address, isReady], | ||
async ([address, isReady]) => { | ||
if (isReady) { | ||
log.value = await read(address); | ||
await listener(address); | ||
isLaoded.value = true; | ||
} | ||
}, | ||
{ immediate: true } | ||
); | ||
|
||
return { | ||
log, | ||
isLaoded | ||
}; | ||
}; |
Oops, something went wrong.