diff --git a/health-check/adapter/states.go b/health-check/adapter/states.go
index 4174dce..f55f134 100644
--- a/health-check/adapter/states.go
+++ b/health-check/adapter/states.go
@@ -1,14 +1,18 @@
package adapter
type States struct {
- Timestamp string `json:"timestamp"`
- State []NodeState `json:"state"`
+ Timestamp string `json:"timestamp"`
+ State HealthInfo `json:"healthinfo"`
}
type NodeState struct {
NodeID int `json:"nid"`
State bool `json:"state"`
}
+type HealthInfo struct {
+ SinkID int `json:"sid"`
+ State []NodeState `json:"state"`
+}
// type HealthInfo struct {
// UUID string `json:"n_uuid"`
diff --git a/health-check/dataService/memory/statusRepo.go b/health-check/dataService/memory/statusRepo.go
index 2c29d43..30320d4 100644
--- a/health-check/dataService/memory/statusRepo.go
+++ b/health-check/dataService/memory/statusRepo.go
@@ -1,6 +1,7 @@
package memory
import (
+ "log"
"sync"
"time"
@@ -16,7 +17,7 @@ var (
type statusRepo struct {
mu *sync.RWMutex
// map[sinkID]map[nodeID]
- table map[int]map[int]model.Status
+ table map[int]map[int]model.Status // 이차원 맵 model.Status가 원소 (0,1,2)
}
var statusTable *statusRepo
@@ -41,7 +42,7 @@ func (sr *statusRepo) Unlock() {
sr.mu.Unlock()
}
-func (sr *statusRepo) UpdateTable(sinkID int, states adapter.States) []model.NodeStatus {
+func (sr *statusRepo) UpdateTable(states adapter.States) model.SinkStatus { // ID 번째 싱크를 업데이트 한다.
t, err := time.ParseInLocation(timeFmt, states.Timestamp, loc)
if err != nil {
t = time.Now()
@@ -50,18 +51,19 @@ func (sr *statusRepo) UpdateTable(sinkID int, states adapter.States) []model.Nod
sr.mu.Lock()
defer sr.mu.Unlock()
- if _, ok := sr.table[sinkID]; !ok {
- sr.table[sinkID] = map[int]model.Status{}
+ if _, ok := sr.table[states.State.SinkID]; !ok {
+ sr.table[states.State.SinkID] = map[int]model.Status{}
}
- return sr.updateNodeStatus(sinkID, states.State, t)
+ return sr.updateNodeStatus(states.State.SinkID, states.State.State, t)
}
-func (sr *statusRepo) updateNodeStatus(sinkID int, ns []adapter.NodeState, t time.Time) []model.NodeStatus {
+func (sr *statusRepo) updateNodeStatus(sinkID int, ns []adapter.NodeState, t time.Time) model.SinkStatus { // 어답더 계층의 NodeState상태와 메모리 계층의 statusRepo의 status table을 동기화시켜 주는 것
res := []model.NodeStatus{}
+ rres := model.SinkStatus{}
nsTable := map[int]bool{}
// update the status checked from the sink node
- for _, v := range ns {
+ for _, v := range ns { // v는 NodeSate 배열 중 한 원소
nsTable[v.NodeID] = true
nodeState, ok := sr.table[sinkID][v.NodeID]
// if new nodeState, regist new state
@@ -79,6 +81,7 @@ func (sr *statusRepo) updateNodeStatus(sinkID int, ns []adapter.NodeState, t tim
// if the state is not confirmed from the sink node
// check timeout and drop state from table
+ // sr.table[sinkID][K]랑 nsTable[k]가 존재하지 않을 경우 제거, 존재할 경우 업데이트
for k, v := range sr.table[sinkID] {
if _, ok := nsTable[k]; !ok {
if v.CheckDrop() {
@@ -90,7 +93,11 @@ func (sr *statusRepo) updateNodeStatus(sinkID int, ns []adapter.NodeState, t tim
}
}
- return res
+ for i, j := range sr.table {
+ log.Println(i, ":", j)
+ }
+ rres = model.SinkStatus{SinkID: sinkID, Satates: res}
+ return rres
}
// func (sr *statusRepo) GetKeys() []string {
diff --git a/health-check/domain/model/status.go b/health-check/domain/model/status.go
index 0fc4587..8262f53 100644
--- a/health-check/domain/model/status.go
+++ b/health-check/domain/model/status.go
@@ -2,32 +2,36 @@ package model
import (
"time"
-
- "github.com/KumKeeHyun/PDK/health-check/setting"
)
const (
- RED = 0
- YELLOW = 1
- GREEN = 2
+ RED = 0 // 미동작
+ YELLOW = 1 // 형태 바뀔 경우 가운데서 중재 단계
+ GREEN = 2 // 동작
)
+type SinkStatus struct {
+ SinkID int `json:"sid"`
+ Satates []NodeStatus `json:"states"`
+}
+
+
type NodeStatus struct {
NodeID int `json:"nid"`
State int `json:"state"`
}
+
+
type Status struct {
State int `json:"state"`
Work bool `json:"work"`
- Count int `json:"count"`
LastConnect time.Time `json:"last_connect"`
}
-func NewStatus(work bool, t time.Time) Status {
+func NewStatus(work bool, t time.Time) Status { // 인자로 받은 work 여부로 Status 구조체 설정
res := Status{
Work: work,
- Count: -1,
LastConnect: t,
}
if work {
@@ -38,53 +42,40 @@ func NewStatus(work bool, t time.Time) Status {
return res
}
-func (s *Status) setState(v int) {
+func (s *Status) setState(v int) { // 인자로 받은 v로 Status구조체 변경
s.State = v
switch v {
case RED:
- s.Count = -1
s.Work = false
case GREEN:
- s.Count = -1
s.Work = true
case YELLOW:
- s.Count = setting.StatusSetting.Count
s.Work = !s.Work
}
}
-func (s *Status) decreaseCnt() {
- if s.Count >= 0 {
- s.Count--
- }
-}
-
func (s *Status) UpdateState(work bool, t time.Time) bool {
isChange := false
// Update time for drop
if work {
s.LastConnect = t
}
- if s.Work != work {
+ if s.State == YELLOW {
+ if work {
+ s.setState(GREEN)
+ } else {
+ s.setState(RED)
+ }
+ isChange = true
+ } else if s.Work != work {
s.setState(YELLOW)
isChange = true
- } else {
- s.decreaseCnt()
- if s.Count == 0 {
- if s.Work {
- s.setState(GREEN)
- } else {
- s.setState(RED)
- }
- isChange = true
- }
}
return isChange
}
-
func (s *Status) CheckDrop() bool {
s.setState(RED)
now := time.Now()
- timeout := s.LastConnect.Add(time.Duration(setting.StatusSetting.Drop) * time.Hour)
+ timeout := time.Now() //s.LastConnect.Add(time.Duration(setting.StatusSetting.Drop) * time.Hour)
return now.After(timeout)
}
diff --git a/health-check/domain/repository/statusRepo.go b/health-check/domain/repository/statusRepo.go
index cfd6e7e..40eec6e 100644
--- a/health-check/domain/repository/statusRepo.go
+++ b/health-check/domain/repository/statusRepo.go
@@ -6,5 +6,5 @@ import (
)
type StatusRepo interface {
- UpdateTable(sinkID int, states adapter.States) []model.NodeStatus
+ UpdateTable(states adapter.States) model.SinkStatus
}
diff --git a/health-check/go.sum b/health-check/go.sum
index d46f6f8..125d8cc 100644
--- a/health-check/go.sum
+++ b/health-check/go.sum
@@ -1,6 +1,7 @@
github.com/KumKeeHyun/PDK v0.0.0-20200925133928-52ab7f87b199 h1:oatxng65jfuNO8rbSf/Jb7oEy7yCEgvLP+cAy5fnkLU=
github.com/KumKeeHyun/PDK/health-check v0.0.0-20200925133928-52ab7f87b199 h1:dLAJIAke48kBX/DkNB77mItO/q6LoDSFTQawG8ParHM=
github.com/KumKeeHyun/PDK/health-check v0.0.0-20200925133928-52ab7f87b199/go.mod h1:ztuzK68BTutIOHO2Kefmo9VUGvqtOvc4YqPuREPZzEs=
+github.com/KumKeeHyun/toiot v0.0.0-20201116030134-35ec72890c25 h1:DKbvg3iJcV9cG2Xs/Ud68kt0Z8HIji5nG7YSe+nAVHE=
github.com/Shopify/sarama v1.27.0 h1:tqo2zmyzPf1+gwTTwhI6W+EXDw4PVSczynpHKFtVAmo=
github.com/Shopify/sarama v1.27.0/go.mod h1:aCdj6ymI8uyPEux1JJ9gcaDT6cinjGhNCAhs54taSUo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
@@ -78,6 +79,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200528225125-3c3fba18258b h1:IYiJPiJfzktmDAO1HQiwjMjwjlYKHAL7KzeD544RJPs=
golang.org/x/net v0.0.0-20200528225125-3c3fba18258b/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
diff --git a/health-check/main.go b/health-check/main.go
index 7ad0651..45db4bd 100644
--- a/health-check/main.go
+++ b/health-check/main.go
@@ -8,7 +8,6 @@ import (
"syscall"
"github.com/KumKeeHyun/toiot/health-check/dataService/memory"
- "github.com/KumKeeHyun/toiot/health-check/setting"
"github.com/KumKeeHyun/toiot/health-check/usecase/healthCheckUC"
"github.com/KumKeeHyun/toiot/health-check/usecase/websocketUC"
"github.com/gin-gonic/gin"
@@ -20,6 +19,7 @@ func main() {
event := make(chan interface{}, 10)
_ = healthCheckUC.NewHealthCheckUsecase(sr, event)
+
wu := websocketUC.NewWebsocketUsecase(event)
r := gin.New()
@@ -41,9 +41,10 @@ func main() {
fmt.Println("disconnect websocket!")
})
- go log.Fatal(r.Run(setting.Healthsetting.Server))
+ go log.Fatal(r.Run(":8085"))
sigterm := make(chan os.Signal, 1)
signal.Notify(sigterm, syscall.SIGINT, syscall.SIGTERM)
<-sigterm
+
}
diff --git a/health-check/test/tcp test/c2 b/health-check/test/tcp test/c2
new file mode 100755
index 0000000..d074591
Binary files /dev/null and b/health-check/test/tcp test/c2 differ
diff --git a/health-check/test/tcp test/client.go b/health-check/test/tcp test/client.go
new file mode 100644
index 0000000..5d776a2
--- /dev/null
+++ b/health-check/test/tcp test/client.go
@@ -0,0 +1,83 @@
+// TCP Client
+package main
+
+import (
+ "log"
+ "net"
+)
+
+func main() {
+ conn, err := net.Dial("tcp", "10.5.110.11:5032")
+ if nil != err {
+ log.Fatalf("failed to connect to server")
+ }
+
+ // some event happens
+ conn.Write([]byte(`
+ {
+ "sid": 1,
+ "state": [{
+ "nid": 1,
+ "state": true
+ },{
+ "nid": 2,
+ "state": false
+ },{
+ "nid": 4,
+ "state": false
+ },{
+ "nid": 8,
+ "state": false
+ },{
+ "nid": 27,
+ "state": false
+ }]
+ }
+ `))
+ /*
+ {
+ "sid": 1,
+ "state": [{
+ "nid": 1,
+ "state": false
+ },{
+ "nid": 2,
+ "state": true
+ },{
+ "nid": 4,
+ "state": false
+ },{
+ "nid": 8,
+ "state": true
+ },{
+ "nid": 27,
+ "state": true
+ }]
+ }
+ {
+ "sid": 1,
+ "state": [{
+ "nid": 1,
+ "state": false
+ },{
+ "nid": 2,
+ "state": true
+ },{
+ "nid": 4,
+ "state": false
+ },{
+ "nid": 8,
+ "state": true
+ },{
+ "nid": 27,
+ "state": true
+ }]
+ }
+ */
+ //conn.Write([]byte("005111111111111"))
+ // for {
+ // // heartbeat
+ // conn.Write([]byte("110210101012"))
+ // time.Sleep(time.Duration(3) * time.Second)
+ // }
+}
diff --git a/health-check/usecase/healthCheckUC/healthCheckUsecase.go b/health-check/usecase/healthCheckUC/healthCheckUsecase.go
index 27f9af3..28de547 100644
--- a/health-check/usecase/healthCheckUC/healthCheckUsecase.go
+++ b/health-check/usecase/healthCheckUC/healthCheckUsecase.go
@@ -1,14 +1,14 @@
package healthCheckUC
import (
- "fmt"
- "sync"
+ "encoding/json"
+ "io"
+ "log"
+ "net"
"time"
"github.com/KumKeeHyun/toiot/health-check/adapter"
"github.com/KumKeeHyun/toiot/health-check/domain/repository"
- "github.com/KumKeeHyun/toiot/health-check/setting"
- "github.com/go-resty/resty/v2"
)
type healthCheckUsecase struct {
@@ -21,39 +21,80 @@ func NewHealthCheckUsecase(sr repository.StatusRepo, e chan interface{}) *health
sr: sr,
event: e,
}
+ l, err := net.Listen("tcp", "10.5.110.11:8083") // 포트정보 setting으로 옮겨야 함
+ if nil != err {
+ log.Fatalf("fail to bind address to 5032; err: %v", err)
+ }
+ //defer l.Close()
go func() {
- tick := time.Tick(time.Duration(setting.StatusSetting.Tick) * time.Second)
for {
- select {
- case <-tick:
- hu.healthCheck()
+ conn, err := l.Accept()
+ if nil != err {
+ log.Printf("fail to accept; err: %v", err)
+ continue
}
+ go hu.healthCheck(conn)
}
}()
-
+ /*
+ go func() {
+ tick := time.Tick(time.Duration(setting.StatusSetting.Tick) * time.Second)
+ for {
+ select {
+ case <-tick:
+ hu.healthCheck()
+ }
+ }
+ }()
+ */
return hu
}
-func (hu *healthCheckUsecase) healthCheck() {
- sinks, err := getSinkList()
- if err != nil {
- return
- }
+func (hu *healthCheckUsecase) healthCheck(conn net.Conn) {
- var wg sync.WaitGroup
- for _, sink := range sinks {
- wg.Add(1)
- go func(s adapter.Sink) {
- res := adapter.States{}
- client := resty.New()
- client.SetTimeout(500 * time.Millisecond)
- resp, _ := client.R().SetResult(&res).Get(fmt.Sprintf("http://%s/health-check", s.Addr))
-
- if resp.IsSuccess() {
- hu.event <- hu.sr.UpdateTable(s.ID, res)
+ for {
+ recvBuf := make([]byte, 4096)
+ n, err := conn.Read(recvBuf)
+ if nil != err {
+ if io.EOF == err {
+ log.Printf("connection is closed from client; %v", conn.RemoteAddr().String())
+ return
}
- wg.Done()
- }(sink)
+ log.Printf("fail to receive data; err: %v", err)
+ return
+ }
+ if n > 0 {
+ var healthInfo adapter.HealthInfo
+ var states adapter.States
+
+ recvBuf = ClearPadding(recvBuf)
+ log.Println("recv Buf :", recvBuf)
+ json.Unmarshal(recvBuf, &healthInfo)
+
+ states.State = healthInfo
+ states.Timestamp = string(time.Now().Unix())
+ log.Println("convert to json :", healthInfo)
+ //test_start
+ tmphealth := hu.sr.UpdateTable(states) // 변화가 생긴 것들만 뭘로 변했는지 알려줌 ex : {1 [{1 1} {2 1} {8 0}]}
+ log.Println(tmphealth.Satates)
+
+ hu.event <- tmphealth.Satates
+ //test_end
+
+ //hu.event <- hu.sr.UpdateTable(sinknum, res)
+
+ }
+ }
+}
+
+func ClearPadding(buf []byte) []byte {
+ var res []byte
+ for i := 1; i < 4096; i++ {
+ if (buf[i-1] == 125) && (buf[i] == 0) {
+ res = buf[:i]
+ break
+ }
}
+ return res
}
diff --git a/ui/.env b/ui/.env
new file mode 100644
index 0000000..55dfed2
--- /dev/null
+++ b/ui/.env
@@ -0,0 +1,11 @@
+REACT_APP_DB_IP=10.5.110.11
+REACT_APP_DB_PORT=8081
+REACT_APP_KIBANA_IP=10.5.110.1
+REACT_APP_KIBANA_PORT=5601
+REACT_APP_HEALTHCHECK_IP=10.5.110.11
+REACT_APP_HEALTHCHECK_PORT=8083
+REACT_APP_LOGICCORE_IP=10.5.110.11
+REACT_APP_LOGICCORE_PORT=8081
+REACT_APP_ALARM_IP=0.0.0.0
+REACT_APP_ALARM_PORT=8080
+REACT_APP_KAKAO_MAP_KEY=21ac78abd39b1baa196594d8611e392d
\ No newline at end of file
diff --git a/ui/src/App.tsx b/ui/src/App.tsx
index 8420103..df149d8 100644
--- a/ui/src/App.tsx
+++ b/ui/src/App.tsx
@@ -3,6 +3,7 @@ import { BrowserRouter as Router, Route } from 'react-router-dom';
import Nav from './Navigation';
import SensorManagement from './ManagementComponents/SensorManagement';
import NodeManagement from './ManagementComponents/NodeManagement';
+import ActuatorManagement from './ManagementComponents/ActuatorManagement';
import Dashboard from './KibanaDashboard';
import Visualize from './KibanaVisualize';
import Main from './Home';
@@ -28,6 +29,7 @@ class App extends Component {
+
diff --git a/ui/src/ElemInterface/ElementsInterface.tsx b/ui/src/ElemInterface/ElementsInterface.tsx
index eb19680..d5946bc 100644
--- a/ui/src/ElemInterface/ElementsInterface.tsx
+++ b/ui/src/ElemInterface/ElementsInterface.tsx
@@ -28,6 +28,11 @@ export interface value_list_elem {
index: number;
}
+export interface actuatorListElem {
+ id: number;
+ name: string;
+}
+
// sinkList interface
export interface sinkListElem {
id: number;
@@ -86,8 +91,9 @@ export interface topicOptionsElem {
// node health check
export interface nodeHealthCheckElem {
- n_id: number;
+ nid: number;
state: number;
+ battery: number;
}
// alarm
diff --git a/ui/src/ElemInterface/LcElementsInterface.tsx b/ui/src/ElemInterface/LcElementsInterface.tsx
index 8408cdf..75f0e7a 100644
--- a/ui/src/ElemInterface/LcElementsInterface.tsx
+++ b/ui/src/ElemInterface/LcElementsInterface.tsx
@@ -10,9 +10,14 @@ export interface timeRange {
end: string;
}
+export interface control {
+ value: number;
+ sleep: number;
+}
+
export interface logicElem {
elem: string;
- arg: lcValueArg | lcTimeArg | lcGroupArg | lcActionArg;
+ arg: lcValueArg | lcTimeArg | lcGroupArg | lcActionArg | lcActuator;
}
export interface lcValueArg {
@@ -32,6 +37,11 @@ export interface lcActionArg {
text: string;
}
+export interface lcActuator {
+ aid: number;
+ motion: Array
;
+}
+
export interface logicListElem {
id: string; // request: undefined, receive: number
logic_name: string;
diff --git a/ui/src/LogicCoreComponents/InputCards/InputActionCard.tsx b/ui/src/LogicCoreComponents/InputCards/InputActionCard.tsx
index 3be0e49..5e01743 100644
--- a/ui/src/LogicCoreComponents/InputCards/InputActionCard.tsx
+++ b/ui/src/LogicCoreComponents/InputCards/InputActionCard.tsx
@@ -1,6 +1,8 @@
+import { type } from 'jquery';
import React, { Component } from 'react';
import Select from 'react-select';
-import { logicElem } from '../../ElemInterface/LcElementsInterface';
+import { control, logicElem } from '../../ElemInterface/LcElementsInterface';
+import InputActuatorCard from './InputActuatorCard';
import '../LogicCore.css';
interface InputActionCardProps {
@@ -11,10 +13,11 @@ interface InputActionCardProps {
interface InputActionCardState {
elem: string;
- arg: {
+ arg: {
text: string;
};
}
+
interface actionOptionsElem {
label: string;
value: string;
@@ -31,14 +34,14 @@ class InputActionCard extends Component<
state: InputActionCardState = {
elem: '',
arg: { text: '' },
- };
+ }
// Handle action change (select alarm or email)
handleActionChange = async (e: any) => {
- // Change this state and then..
await this.setState({
elem: e.value,
});
+ console.log(this.state.elem + '!!!!!@@#@####!@#!');
// change parent's state
this.props.handleInputActionCardChange(this.state);
};
@@ -46,7 +49,9 @@ class InputActionCard extends Component<
// Handle text change by typing
handleTextChange = async (e: React.ChangeEvent) => {
await this.setState({
- arg: { text: e.target.value },
+ arg: {
+ text: e.target.value,
+ },
});
this.props.handleInputActionCardChange(this.state);
};
@@ -55,7 +60,9 @@ class InputActionCard extends Component<
let actionOptions: Array = [
{ label: 'alarm', value: 'alarm' },
{ label: 'email', value: 'email' },
+ { label: 'actuator', value: 'actuator'},
];
+
return (
@@ -94,9 +101,9 @@ class InputActionCard extends Component<
-
+ {/*
*/}
{this.state.elem === 'alarm' ? ( // If user select alarm
-
) : this.state.elem === 'email' ? ( // If user select email
-
+
Email address
+ ) : this.state.elem === 'actuator' ? (
+
) : (
)}
-
+ //
);
}
}
diff --git a/ui/src/LogicCoreComponents/InputCards/InputActuatorCard.tsx b/ui/src/LogicCoreComponents/InputCards/InputActuatorCard.tsx
new file mode 100644
index 0000000..0e84750
--- /dev/null
+++ b/ui/src/LogicCoreComponents/InputCards/InputActuatorCard.tsx
@@ -0,0 +1,193 @@
+import { type } from 'jquery';
+import React, { Component } from 'react';
+import Select from 'react-select';
+import { control, logicElem } from '../../ElemInterface/LcElementsInterface';
+import '../LogicCore.css';
+
+interface InputActionCardProps {
+ handleInputActionCardChange: (value: logicElem) => void;
+ //handleRemoveInputActionCardClick: () => void;
+ //index: number;
+}
+
+interface InputActionCardState {
+ elem: string;
+ arg: {
+ aid: number;
+ motion: Array;
+ };
+}
+interface actionOptionsElem {
+ label: string;
+ value: string;
+}
+
+/*
+InputActionCard
+- Get input of action element
+*/
+class InputActionCard extends Component<
+ InputActionCardProps,
+ InputActionCardState
+> {
+ state: InputActionCardState = {
+ elem: 'actuator',
+ arg: {
+ aid: 0,
+ motion:[{ value: 0, sleep: 0 }]
+ },
+ };
+
+ // Handle action change (select alarm or email)
+ handleActionChange = async (e: any) => {
+ // Change this state and then..
+ if (e.value === 'motor') {
+ await this.setState({
+ arg: {
+ aid: 1,
+ motion: this.state.arg.motion,
+ }
+ });
+ console.log(this.state.arg.aid);
+ }
+ else if (e.value === 'switch') {
+ await this.setState({
+ arg: {
+ aid: 2,
+ motion: this.state.arg.motion,
+ }
+ });
+ }
+ this.props.handleInputActionCardChange(this.state);
+ };
+
+ // Handle text change by typing
+ handleTextChange = async (e: React.ChangeEvent) => {
+ await this.setState({
+ arg: {
+ aid: this.state.arg.aid,
+ motion: this.state.arg.motion,
+ },
+ });
+ this.props.handleInputActionCardChange(this.state);
+ };
+
+ handleControlChange = (idx: number) => async (e:any) => {
+ const new_motion_elem = this.state.arg.motion.map(
+ (motionElem: control, sidx: number) => {
+ if (idx !== sidx) return motionElem;
+ if (e.target.id === 'actuator_value')
+ return { ...motionElem, value: parseInt(e.target.value) };
+ return { ...motionElem, sleep: parseInt(e.target.value) };
+
+ }
+ );
+
+ await this.setState({
+ arg: {
+ aid: this.state.arg.aid,
+ motion: new_motion_elem
+ }
+ });
+
+ this.props.handleInputActionCardChange(this.state);
+ };
+
+ handleAddClick = async () => {
+ await this.setState({
+ arg: {
+ aid: this.state.arg.aid,
+ motion: [...this.state.arg.motion, {value: 0, sleep: 0}],
+ },
+ });
+ this.props.handleInputActionCardChange(this.state);
+ };
+
+ handleRemoveClick = (idx: number) => async () => {
+ await this.setState({
+ arg: {
+ aid: this.state.arg.aid,
+ motion: this.state.arg.motion.filter(
+ (s: any, sidx: number) => idx !== sidx
+ ),
+ },
+ });
+ this.props.handleInputActionCardChange(this.state)
+ };
+
+ render() {
+ let actuatorOptios: Array = [
+ { label: 'motor', value: 'motor'},
+ { label: 'switch', value: 'switch'},
+ ]
+ return (
+
+
+
+
+
+
+
+
+ {this.state.arg.motion.map((Control: control, idx: number) => (
+
+
value
+
+
+
sleep
+
+< button
+ className="btn btn-sm"
+ type="button"
+ id="button-addon2"
+ onClick={this.handleRemoveClick(idx)}
+ >
+
+
+
+ ))}
+
+
+ );
+ }
+}
+
+export default InputActionCard;
diff --git a/ui/src/LogicCoreComponents/RegisterLogic.tsx b/ui/src/LogicCoreComponents/RegisterLogic.tsx
index 774737b..7935cd2 100644
--- a/ui/src/LogicCoreComponents/RegisterLogic.tsx
+++ b/ui/src/LogicCoreComponents/RegisterLogic.tsx
@@ -146,6 +146,7 @@ class RegisterLogic extends Component<{}, RegisterLogicState> {
handleActionCardChange = (idx: number) => (selectedAction: logicElem) => {
// Action card is updated dynamic. It can be added or removed freely.
// so find changing field by using received idx and change state.
+ console.log(selectedAction.elem + "!!!!");
const new_selected_action = this.state.selected_action.map(
(action: logicElem, sidx: number) => {
if (idx !== sidx) return action;
@@ -237,7 +238,9 @@ class RegisterLogic extends Component<{}, RegisterLogicState> {
this.state.selected_action
);
- // Filter elem: 'empty' field
+ console.log(this.state.selected_action[0] + "!@!@!@!!@@!@");
+
+ // Filter elem: 'empty' fie ld
elems = elems.filter(function (logic) {
return logic.elem !== 'empty';
});
diff --git a/ui/src/LogicCoreComponents/ShowCards/ShowActionCard.tsx b/ui/src/LogicCoreComponents/ShowCards/ShowActionCard.tsx
index 1286e88..ef771b4 100644
--- a/ui/src/LogicCoreComponents/ShowCards/ShowActionCard.tsx
+++ b/ui/src/LogicCoreComponents/ShowCards/ShowActionCard.tsx
@@ -3,6 +3,8 @@ import '../LogicCore.css';
import {
logicElem,
lcActionArg,
+ lcActuator,
+ control,
} from '../../ElemInterface/LcElementsInterface';
interface ShowActionCardProps {
@@ -16,6 +18,10 @@ ShowActionCard
class ShowActionCard extends Component {
render() {
var action = this.props.logic_elem.arg as lcActionArg;
+ var control = (this.props.logic_elem.arg as lcActuator).motion;
+ var motion_name = (this.props.logic_elem.arg as lcActuator).aid;
+ if (motion_name === 1) var name = 'motor';
+ else name = 'switch';
return (
@@ -41,6 +47,20 @@ class ShowActionCard extends Component {
: {action.text}
+ ) : this.props.logic_elem.elem === 'actuator' ? (
+
+ {control.map((control: control, idx: number) => (
+
+
+ [actuator #{idx}]
+
+
+
+ motion: {name} / value: {control.value} / sleep: {control.sleep}
+
+
+ ))}
+
) : (
)}
diff --git a/ui/src/LogicCoreComponents/ShowCards/ShowValueCard.tsx b/ui/src/LogicCoreComponents/ShowCards/ShowValueCard.tsx
index e846373..1fac4e9 100644
--- a/ui/src/LogicCoreComponents/ShowCards/ShowValueCard.tsx
+++ b/ui/src/LogicCoreComponents/ShowCards/ShowValueCard.tsx
@@ -33,7 +33,7 @@ class ShowValueCard extends Component {
{range.map((range: numRange, idx: number) => (
- range #{idx}
+ [range #{idx}]
diff --git a/ui/src/LogicCoreComponents/ShowLogic.tsx b/ui/src/LogicCoreComponents/ShowLogic.tsx
index 6161d4b..ffd3c50 100644
--- a/ui/src/LogicCoreComponents/ShowLogic.tsx
+++ b/ui/src/LogicCoreComponents/ShowLogic.tsx
@@ -76,7 +76,7 @@ class ShowLogic extends Component {
))}
{this.props.logic.elems
.filter(function (element) {
- return element.elem === 'alarm' || element.elem === 'email';
+ return element.elem === 'alarm' || element.elem === 'email' || element.elem === 'actuator';
})
.map((actionCard: logicElem, idx: number) => (
diff --git a/ui/src/ManagementComponents/ActuatorManagement.tsx b/ui/src/ManagementComponents/ActuatorManagement.tsx
new file mode 100644
index 0000000..a642a90
--- /dev/null
+++ b/ui/src/ManagementComponents/ActuatorManagement.tsx
@@ -0,0 +1,34 @@
+import React, { Component } from 'react';
+import RegisterActuator from './Register/RegisterActuator';
+import ActuatorTable from './Table/ActuatorTable';
+
+/*
+SensorManagement
+- Manage sensor table, register sensor
+*/
+class ActuatorManagement extends Component {
+ render() {
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+ }
+}
+
+export default ActuatorManagement;
diff --git a/ui/src/ManagementComponents/Register/RegisterActuator.tsx b/ui/src/ManagementComponents/Register/RegisterActuator.tsx
new file mode 100644
index 0000000..a02759e
--- /dev/null
+++ b/ui/src/ManagementComponents/Register/RegisterActuator.tsx
@@ -0,0 +1,124 @@
+import React, { Component } from 'react';
+import { ACTUATOR_URL } from '../../defineUrl';
+
+interface RegisterActuatorState {
+ name: string;
+ nameValid: boolean;
+}
+
+class RegisterActuator extends Component<{}, RegisterActuatorState> {
+ state: RegisterActuatorState = {
+ name: '',
+ nameValid: false,
+ };
+
+ handleNameChange = (e: React.ChangeEvent) => {
+ if (e.target.value.length > 0) {
+ this.setState({
+ name: e.target.value,
+ nameValid: true,
+ });
+ } else {
+ this.setState({
+ name: e.target.value,
+ nameValid: false,
+ });
+ }
+ console.log(this.state.name + '@@2!!@!@');
+ };
+
+ handleSubmit = (e: React.MouseEvent) => {
+ e.preventDefault();
+
+ var url = ACTUATOR_URL;
+ var data = this.state;
+
+ if (!this.state.nameValid) {
+ alert('Please enter actuator name.');
+ return;
+ }
+
+ var submitValid: boolean;
+ submitValid = window.confirm('Are you sure to register this actuator?');
+ if (!submitValid) {
+ return;
+ }
+ alert('data : '+data+', url : ' + url);
+ fetch(url, {
+ method: 'POST', // or 'PUT'
+ body: JSON.stringify(data),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ })
+ .then((res) => res.json())
+ .then((response) => console.log('Success:', JSON.stringify(response)))
+ .catch((error) => console.error('Error:', error))
+ .then(() => window.location.reload(false));
+ };
+
+ render() {
+ return (
+ <>
+
+
+
+
+
+ Register actuator
+
+
+
+
+
+
+
+ >
+ );
+ }
+}
+
+export default RegisterActuator;
\ No newline at end of file
diff --git a/ui/src/ManagementComponents/Table/ActuatorTable.tsx b/ui/src/ManagementComponents/Table/ActuatorTable.tsx
new file mode 100644
index 0000000..8d7b10d
--- /dev/null
+++ b/ui/src/ManagementComponents/Table/ActuatorTable.tsx
@@ -0,0 +1,119 @@
+import React, { Component } from 'react';
+import { ACTUATOR_URL } from '../../defineUrl';
+import { actuatorListElem } from '../../ElemInterface/ElementsInterface';
+import Pagination from '../Pagination';
+
+//import DeleteRequest from './DeleteRequest'
+
+interface ActuatorTableState {
+ actuatorList: Array
+ currentPage: number;
+ pages: number;
+}
+
+/*
+SensorTable
+- Show up sensor list.
+*/
+class ActuatorTable extends Component<{}, ActuatorTableState> {
+ state: ActuatorTableState = {
+ actuatorList: [],
+ currentPage: 1,
+ pages: 0,
+ };
+
+ componentDidMount() {
+ this.getsensorList(this.state.currentPage);
+ }
+
+ // Get sensor list from backend per page
+ getsensorList(page: number) {
+ var url = ACTUATOR_URL + '?page=' + page;
+
+ fetch(url)
+ .then((res) => res.json())
+ .then((data) => {
+ page === 1
+ ? this.setState({ actuatorList: data.actuators, pages: data.pages })
+ : this.setState({ actuatorList: data.actuators });
+ })
+ .catch((error) => console.error('Error:', error));
+ }
+
+ // Handle click event of the Remove button
+ handleRemoveClick = (actuator_id: number) => () => {
+ var url = ACTUATOR_URL + '/' + actuator_id;
+
+ fetch(url, {
+ method: 'DELETE',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ })
+ .then((res) => res.json())
+ .catch((error) => console.error('Error:', error))
+ .then(() => window.location.reload(false));
+ };
+
+ handlePageChange = (page: number) => {
+ this.setState({ currentPage: page });
+ this.getsensorList(page);
+ };
+
+ render() {
+ return (
+ <>
+
+
+
+ | # |
+ name |
+ id |
+ |
+
+
+
+ {this.state.actuatorList.map(
+ (actuator: actuatorListElem, idx: number) => (
+
+ | {idx + 10 * (this.state.currentPage - 1)} |
+ {actuator.name} |
+ {actuator.id} |
+
+
+ |
+
+ )
+ )}
+
+
+
+ >
+ );
+ }
+}
+
+export default ActuatorTable;
diff --git a/ui/src/ManagementComponents/Table/MapNodeTable.tsx b/ui/src/ManagementComponents/Table/MapNodeTable.tsx
index a5e967b..e56e51b 100644
--- a/ui/src/ManagementComponents/Table/MapNodeTable.tsx
+++ b/ui/src/ManagementComponents/Table/MapNodeTable.tsx
@@ -39,7 +39,7 @@ class MapNodeTable extends Component {
// Find node state(health) and represent as colors (red - yellow - green, gray)
findNodeState = (id: number) => {
for (let prop in this.props.nodeState) {
- if (this.props.nodeState[prop].n_id === id) {
+ if (this.props.nodeState[prop].nid === id) {
return (
{
return | ● | ;
};
+ findNodeBattery = (id: number) => {
+ for (let prop in this.props.nodeState) {
+ if (this.props.nodeState[prop].nid === id) {
+ var battery = this.props.nodeState[prop].battery;
+ if ( battery === 0 )
+ return External power |
+ if ( battery === 255 )
+ return Not measurable |
+ // return {battery} |
+ }
+ }
+ return 200 |
+ };
+
render() {
return (
<>
@@ -65,6 +79,7 @@ class MapNodeTable extends Component {
id |
sensors |
health |
+ battery |
|
@@ -76,6 +91,7 @@ class MapNodeTable extends Component {
{node.id} |
{node.sensors.map((sensor: any) => sensor.name + ', ')} |
{this.findNodeState(node.id)}
+ {this.findNodeBattery(node.id)}
|