Initial commit

This commit is contained in:
Gašper Dobrovoljc 2023-03-13 14:50:49 +01:00
commit 0c0d82db42
No known key found for this signature in database
GPG Key ID: 0E7E037018CFA5A5
9 changed files with 298 additions and 0 deletions

4
.prettierrc Normal file
View File

@ -0,0 +1,4 @@
{
"singleQuote": true,
"trailingComma": "all"
}

8
go.mod Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);
});