Initial commit
This commit is contained in:
commit
0c0d82db42
4
.prettierrc
Normal file
4
.prettierrc
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all"
|
||||||
|
}
|
8
go.mod
Normal file
8
go.mod
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
module github.com/gapidobri/siemens-ws
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/danclive/snap7-go v0.1.2
|
||||||
|
github.com/gorilla/websocket v1.5.0
|
||||||
|
)
|
4
go.sum
Normal file
4
go.sum
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
github.com/danclive/snap7-go v0.1.2 h1:DL4HWS9efPzJfTk1x9As0QUwc/Y3C0oTbm6plvHnNWg=
|
||||||
|
github.com/danclive/snap7-go v0.1.2/go.mod h1:zON3ZLTb9Cr3GJAWGkMzJ8gf/o2Sqyd/MrZ1wxQsiQw=
|
||||||
|
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||||
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
18
hardware/hardware.go
Normal file
18
hardware/hardware.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package hardware
|
||||||
|
|
||||||
|
type (
|
||||||
|
Hardware interface {
|
||||||
|
Read() (uint16, error)
|
||||||
|
}
|
||||||
|
Client struct {
|
||||||
|
hardware Hardware
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewClient(h Hardware) Client {
|
||||||
|
return Client{hardware: h}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Client) Read() (uint16, error) {
|
||||||
|
return c.hardware.Read()
|
||||||
|
}
|
22
hardware/mock.go
Normal file
22
hardware/mock.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package hardware
|
||||||
|
|
||||||
|
type Mock struct {
|
||||||
|
currValue int16
|
||||||
|
delta int16
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMock() *Mock {
|
||||||
|
return &Mock{currValue: 0, delta: 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mock) Read() (uint16, error) {
|
||||||
|
m.currValue += m.delta
|
||||||
|
|
||||||
|
if m.currValue >= 100 {
|
||||||
|
m.delta = -1
|
||||||
|
} else if m.currValue <= 0 {
|
||||||
|
m.delta = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint16(m.currValue), nil
|
||||||
|
}
|
26
hardware/siemens.go
Normal file
26
hardware/siemens.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package hardware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
|
||||||
|
snap7 "github.com/danclive/snap7-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Siemens struct {
|
||||||
|
client snap7.Snap7Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSiemens(client snap7.Snap7Client) Siemens {
|
||||||
|
return Siemens{client: client}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Siemens) Read() (uint16, error) {
|
||||||
|
db, err := s.client.DBRead(1, 0, 8)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
value := binary.BigEndian.Uint16(db[2:4])
|
||||||
|
|
||||||
|
return value, nil
|
||||||
|
}
|
87
main.go
Normal file
87
main.go
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/danclive/snap7-go"
|
||||||
|
"github.com/gapidobri/siemens-ws/hardware"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
upgrader = websocket.Upgrader{
|
||||||
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
clients = []chan uint16{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
siemens, err := snap7.ConnentTo("192.168.117.222", 0, 1, 0)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// client := hardware.NewClient(hardware.NewMock())
|
||||||
|
client := hardware.NewSiemens(siemens)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
val, err := client.Read()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("read err:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(val)
|
||||||
|
|
||||||
|
for _, c := range clients {
|
||||||
|
c <- val
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Println("open handler")
|
||||||
|
|
||||||
|
c, err := upgrader.Upgrade(w, r, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("upgrade err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
dataCh := make(chan uint16)
|
||||||
|
|
||||||
|
clients = append(clients, dataCh)
|
||||||
|
|
||||||
|
for {
|
||||||
|
val, more := <-dataCh
|
||||||
|
if !more {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err = c.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("%d", val)))
|
||||||
|
if err != nil {
|
||||||
|
log.Println("write err:", err)
|
||||||
|
fmt.Println("close handler")
|
||||||
|
c.Close()
|
||||||
|
close(dataCh)
|
||||||
|
for i, c := range clients {
|
||||||
|
if c == dataCh {
|
||||||
|
clients = append(clients[:i], clients[i+1:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
log.Fatal(http.ListenAndServe(":1234", nil))
|
||||||
|
|
||||||
|
}
|
47
static/index.html
Normal file
47
static/index.html
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Document</title>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/luxon@1.27.0"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.0.0"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-streaming@2.0.0"></script>
|
||||||
|
|
||||||
|
<script defer src="script.js"></script>
|
||||||
|
</head>
|
||||||
|
<style>
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
td,
|
||||||
|
tr {
|
||||||
|
border: 1px solid black;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<span id="data"></span>
|
||||||
|
<br />
|
||||||
|
<label for="target">
|
||||||
|
Target
|
||||||
|
<input type="range" min="0" max="100" id="target" />
|
||||||
|
</label>
|
||||||
|
<div class="row">
|
||||||
|
<canvas id="chart"></canvas>
|
||||||
|
|
||||||
|
<table id="table">
|
||||||
|
<thead>
|
||||||
|
<th>Time</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</thead>
|
||||||
|
<tbody></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
82
static/script.js
Normal file
82
static/script.js
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
const dataNode = document.getElementById('data');
|
||||||
|
const ctx = document.getElementById('chart');
|
||||||
|
const table = document.getElementById('table');
|
||||||
|
const target = document.getElementById('target');
|
||||||
|
|
||||||
|
const socket = new WebSocket('ws://127.0.0.1:1234');
|
||||||
|
|
||||||
|
socket.addEventListener('open', (e) => {
|
||||||
|
console.log('connection opened');
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.addEventListener('close', (e) => {
|
||||||
|
console.log('connection closed');
|
||||||
|
});
|
||||||
|
|
||||||
|
Chart.defaults.set('plugins.streaming', {
|
||||||
|
duration: 20000,
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = [];
|
||||||
|
const labels = [];
|
||||||
|
const targets = [];
|
||||||
|
|
||||||
|
const chart = new Chart(ctx, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels,
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: 'Value',
|
||||||
|
data: data,
|
||||||
|
borderWidth: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Target',
|
||||||
|
data: targets,
|
||||||
|
borderWidth: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
animations: false,
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
chart.resize(1300, 600);
|
||||||
|
|
||||||
|
function updateTable(data) {
|
||||||
|
if (table.rows.length == 20) {
|
||||||
|
table.rows[table.rows.length - 1].remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
const tr = table.insertRow(1);
|
||||||
|
tr.innerHTML = `
|
||||||
|
<td>${new Date().toLocaleString()}</td>
|
||||||
|
<td>${data}</td>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.addEventListener('message', (e) => {
|
||||||
|
const value = Math.round(parseInt(e.data) / 2.83) / 100;
|
||||||
|
|
||||||
|
dataNode.innerText = value;
|
||||||
|
data.push(value);
|
||||||
|
labels.push(new Date().toLocaleString());
|
||||||
|
if (data.length > 100) {
|
||||||
|
data.shift();
|
||||||
|
labels.shift();
|
||||||
|
targets.shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
chart.update();
|
||||||
|
|
||||||
|
updateTable(value);
|
||||||
|
|
||||||
|
targets.push(target.value);
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user