mirror of
https://github.com/UbiquitousIntelligentSystemBINUS/SleepMonitoringSystemUsingEdgeCache.git
synced 2026-07-10 07:23:33 +07:00
Delete Thesis_Code directory
This commit is contained in:
@@ -1,44 +0,0 @@
|
||||
## Docker Testing
|
||||
|
||||
version: "3.7"
|
||||
services:
|
||||
mqtt-broker:
|
||||
image: eclipse-mosquitto
|
||||
container_name: mqtt-broker
|
||||
ports:
|
||||
- "1883:1883" #default mqtt port
|
||||
- "9001:9001" #default mqtt port for websockets
|
||||
volumes:
|
||||
- ./mqtt/config:/mosquitto/config
|
||||
- ./mqtt/data:/mosquitto/data
|
||||
- ./mqtt/log:/mosquitto/log/mosquitto.log
|
||||
|
||||
mqtt-client:
|
||||
image: emqx/mqttx-web
|
||||
container_name: mqtt-client
|
||||
ports:
|
||||
- "9000:80"
|
||||
|
||||
db:
|
||||
container_name: db
|
||||
image: postgres:14.1-alpine
|
||||
restart: always
|
||||
environment:
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
ports:
|
||||
- '5432:5432'
|
||||
volumes:
|
||||
- db:/var/lib/postgresql/data
|
||||
|
||||
|
||||
volumes:
|
||||
config:
|
||||
data:
|
||||
log:
|
||||
db:
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: mqtt
|
||||
external: true
|
||||
@@ -1,37 +0,0 @@
|
||||
module github.com/stanleydv12/gateway-classification
|
||||
|
||||
go 1.21.3
|
||||
|
||||
require (
|
||||
github.com/eclipse/paho.mqtt.golang v1.4.3
|
||||
github.com/galeone/tensorflow/tensorflow/go v0.0.0-20221023090153-6b7fa0680c3e
|
||||
github.com/galeone/tfgo v0.0.0-20230715013254-16113111dc99
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/chzyer/readline v1.5.1 // indirect
|
||||
github.com/google/go-cmp v0.5.8 // indirect
|
||||
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect
|
||||
github.com/gorilla/websocket v1.5.1 // indirect
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20240205174729-1f824a1a9b87 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jackc/pgx/v5 v5.4.3 // indirect
|
||||
github.com/stretchr/testify v1.8.4 // indirect
|
||||
github.com/tensorflow/tensorflow v2.15.0+incompatible // indirect
|
||||
golang.org/x/sync v0.6.0 // indirect
|
||||
golang.org/x/sys v0.17.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
golang.org/x/crypto v0.18.0 // indirect
|
||||
golang.org/x/net v0.20.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gorm.io/driver/postgres v1.5.4
|
||||
gorm.io/gorm v1.25.5
|
||||
)
|
||||
@@ -1,69 +0,0 @@
|
||||
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
||||
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
|
||||
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik=
|
||||
github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
|
||||
github.com/galeone/tensorflow/tensorflow/go v0.0.0-20221023090153-6b7fa0680c3e h1:9+2AEFZymTi25FIIcDwuzcOPH04z9+fV6XeLiGORPDI=
|
||||
github.com/galeone/tensorflow/tensorflow/go v0.0.0-20221023090153-6b7fa0680c3e/go.mod h1:TelZuq26kz2jysARBwOrTv16629hyUsHmIoj54QqyFo=
|
||||
github.com/galeone/tfgo v0.0.0-20230715013254-16113111dc99 h1:8Bt1P/zy1gb37L4n8CGgp1qmFwBV5729kxVfj0sqhJk=
|
||||
github.com/galeone/tfgo v0.0.0-20230715013254-16113111dc99/go.mod h1:3YgYBeIX42t83uP27Bd4bSMxTnQhSbxl0pYSkCDB1tc=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo=
|
||||
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20240205174729-1f824a1a9b87 h1:IG+58MeF0K/wSXknV4FMOABt6B4VZCguRDxYSCJqWb4=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20240205174729-1f824a1a9b87/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
|
||||
github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tensorflow/tensorflow v2.15.0+incompatible h1:qWaan+jC2rrHctJliI+TSAwLGdCoQdsrwN7YddLv81Y=
|
||||
github.com/tensorflow/tensorflow v2.15.0+incompatible/go.mod h1:itOSERT4trABok4UOoG+X4BoKds9F3rIsySdn+Lvu90=
|
||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo=
|
||||
gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0=
|
||||
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
|
||||
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
@@ -1,28 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/stanleydv12/gateway-classification/src/database"
|
||||
"github.com/stanleydv12/gateway-classification/src/handler"
|
||||
"github.com/stanleydv12/gateway-classification/src/mqtt"
|
||||
)
|
||||
|
||||
// main initializes the database and MQTT setup, then starts listening for MQTT messages.
|
||||
//
|
||||
// No parameters.
|
||||
// No return types.
|
||||
func main() {
|
||||
// Setup Database
|
||||
db := database.SetupDatabase()
|
||||
handler.SetDBInstance(db)
|
||||
|
||||
// Setup Mqtt
|
||||
mqtt.SetupMqtt()
|
||||
|
||||
// Application set to listen
|
||||
mqtt.Sub(mqtt.Client)
|
||||
|
||||
handler.StartTimer()
|
||||
|
||||
// Block the main function with a select statement
|
||||
select {}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
persistence true
|
||||
persistence_location /mosquitto/data/
|
||||
log_dest file /mosquitto/log/mosquitto.log
|
||||
allow_anonymous true
|
||||
listener 1883 0.0.0.0
|
||||
listener 9001 0.0.0.0
|
||||
protocol websockets
|
||||
@@ -1,44 +0,0 @@
|
||||
# Panduan Setup MQTT
|
||||
|
||||
Berikut adalah langkah-langkah untuk melakukan setup pada MQTT:
|
||||
1. Buatlah folder mqtt yang didalamnya terdapat 3 folder lain yaitu config, data, dan log.
|
||||
2. Lalu konfigurasi mqtt sesuai kebutuhan pada folder mqtt -> config -> mosquitto.conf
|
||||
|
||||
# Panduan Menjalankan Dockerfile
|
||||
|
||||
Berikut adalah langkah-langkah untuk menjalankan Dockerfile dan membangun image Docker:
|
||||
|
||||
## Langkah 1: Build Docker Image
|
||||
|
||||
```bash
|
||||
docker build -t myapp .
|
||||
```
|
||||
|
||||
## Langkah 2: Kirim Image ke Registry Cloud
|
||||
```bash
|
||||
docker login <registry-url>
|
||||
docker tag <image-name>:<tag> <registry-url>/<username>/<image-name>:<tag>
|
||||
```
|
||||
|
||||
# Panduan Instalasi Kubernetes Cluster menggunakan Terraform
|
||||
|
||||
Berikut adalah langkah-langkah untuk menggunakan Terraform untuk menerapkan kluster Kubernetes di lingkungan Anda.
|
||||
|
||||
## Persyaratan Sebelum Instalasi:
|
||||
|
||||
1. Pastikan Anda memiliki akun layanan cloud (seperti AWS, GCP, atau Azure) dan telah mengkonfigurasi kredensial akses yang sesuai.
|
||||
2. Instalasi Terraform di komputer lokal Anda. Anda dapat mengunduh Terraform dari situs web resmi mereka. Direkomendasikan menggunakan Google Cloud Console dimana sudah terdapat instalasi terraform nya.
|
||||
|
||||
## Langkah-langkah:
|
||||
|
||||
```bash
|
||||
$ terraform init
|
||||
$ terraform plan
|
||||
$ terraform apply
|
||||
```
|
||||
|
||||
# Panduan Testing
|
||||
|
||||
Berikut adalah langkah-langkah untuk melakukan testing menggunakan JMeter:
|
||||
1. Tambahkan plugin MQTT yang terdapat di folder infrastructure pada JMeter.
|
||||
2. Lalu open file dengan tipe .jmx pada folder infrastructure tersebut.
|
||||
@@ -1,112 +0,0 @@
|
||||
package classify
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
type Complex struct {
|
||||
Re float64 // the real part
|
||||
Im float64 // the imaginary part
|
||||
}
|
||||
|
||||
// create a new object with the given real and imaginary parts
|
||||
func NewComplex(real, imag float64) Complex {
|
||||
return Complex{Re: real, Im: imag}
|
||||
}
|
||||
|
||||
// return a string representation of the invoking Complex object
|
||||
func (c Complex) String() string {
|
||||
if c.Im == 0 {
|
||||
return fmt.Sprintf("%g", c.Re)
|
||||
}
|
||||
if c.Re == 0 {
|
||||
return fmt.Sprintf("%gi", c.Im)
|
||||
}
|
||||
if c.Im < 0 {
|
||||
return fmt.Sprintf("%g - %gi", c.Re, -c.Im)
|
||||
}
|
||||
return fmt.Sprintf("%g + %gi", c.Re, c.Im)
|
||||
}
|
||||
|
||||
// return abs/modulus/magnitude
|
||||
func (c Complex) Abs() float64 {
|
||||
return math.Hypot(c.Re, c.Im)
|
||||
}
|
||||
|
||||
// return a new Complex object whose value is (this + b)
|
||||
func (c Complex) Plus(b Complex) Complex {
|
||||
return Complex{c.Re + b.Re, c.Im + b.Im}
|
||||
}
|
||||
|
||||
// return a new Complex object whose value is (this - b)
|
||||
func (c Complex) Minus(b Complex) Complex {
|
||||
return Complex{c.Re - b.Re, c.Im - b.Im}
|
||||
}
|
||||
|
||||
// return a new Complex object whose value is (this * b)
|
||||
func (c Complex) Times(b Complex) Complex {
|
||||
return Complex{c.Re*b.Re - c.Im*b.Im, c.Re*b.Im + c.Im*b.Re}
|
||||
}
|
||||
|
||||
// return a new Complex object whose value is the reciprocal of this
|
||||
func (c Complex) Reciprocal() Complex {
|
||||
scale := c.Re*c.Re + c.Im*c.Im
|
||||
return Complex{c.Re / scale, -c.Im / scale}
|
||||
}
|
||||
|
||||
// return a / b
|
||||
func (c Complex) Divides(b Complex) Complex {
|
||||
return c.Times(b.Reciprocal())
|
||||
}
|
||||
|
||||
// return a new Complex object whose value is the complex sine of this
|
||||
func (c Complex) Sin() Complex {
|
||||
return Complex{math.Sin(c.Re) * math.Cosh(c.Im), math.Cos(c.Re) * math.Sinh(c.Im)}
|
||||
}
|
||||
|
||||
// return a new Complex object whose value is the complex cosine of this
|
||||
func (c Complex) Cos() Complex {
|
||||
return Complex{math.Cos(c.Re) * math.Cosh(c.Im), -math.Sin(c.Re) * math.Sinh(c.Im)}
|
||||
}
|
||||
|
||||
// equals returns true if the given Complex object is equal to the receiver
|
||||
func (c Complex) Equals(x Complex) bool {
|
||||
return c.Re == x.Re && c.Im == x.Im
|
||||
}
|
||||
|
||||
// FFT computes the FFT of a complex sequence x[] of length n.
|
||||
func FFT(x []Complex) []Complex {
|
||||
n := len(x)
|
||||
if n == 1 {
|
||||
return []Complex{x[0]}
|
||||
}
|
||||
|
||||
if n%2 != 0 {
|
||||
panic("n is not a power of 2")
|
||||
}
|
||||
|
||||
// Compute FFT of even terms
|
||||
even := make([]Complex, n/2)
|
||||
for k := 0; k < n/2; k++ {
|
||||
even[k] = x[2*k]
|
||||
}
|
||||
q := FFT(even)
|
||||
|
||||
// Compute FFT of odd terms
|
||||
odd := even // Reuse the array
|
||||
for k := 0; k < n/2; k++ {
|
||||
odd[k] = x[2*k+1]
|
||||
}
|
||||
r := FFT(odd)
|
||||
|
||||
// Combine
|
||||
y := make([]Complex, n)
|
||||
for k := 0; k < n/2; k++ {
|
||||
kth := -2 * math.Pi * float64(k) / float64(n)
|
||||
wk := Complex{math.Cos(kth), math.Sin(kth)}
|
||||
y[k] = q[k].Plus(wk.Times(r[k]))
|
||||
y[k+n/2] = q[k].Minus(wk.Times(r[k]))
|
||||
}
|
||||
return y
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package classify
|
||||
@@ -1,96 +0,0 @@
|
||||
package classify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RealMatrix struct {
|
||||
Rows int
|
||||
Cols int
|
||||
Data [][]float64
|
||||
}
|
||||
|
||||
type Weight struct {
|
||||
W RealMatrix
|
||||
BW RealMatrix
|
||||
}
|
||||
|
||||
type ELMModel struct {
|
||||
InputWeight RealMatrix
|
||||
BiasInputWeight RealMatrix
|
||||
OutputWeight RealMatrix
|
||||
Separator string
|
||||
}
|
||||
|
||||
func NewELMModel(inputWeightFilePath, outputWeightFilePath string) (*ELMModel, error) {
|
||||
var elmModel ELMModel
|
||||
|
||||
inputWeightFileBytes, err := ioutil.ReadFile(inputWeightFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
outputWeightFileBytes, err := ioutil.ReadFile(outputWeightFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
inputWeightFileLines := strings.Split(string(inputWeightFileBytes), "\n")
|
||||
outputWeightFileLines := strings.Split(string(outputWeightFileBytes), "\n")
|
||||
|
||||
weight, err := convertListCsvTo2dArr(inputWeightFileLines, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
elmModel.InputWeight = weight.W
|
||||
elmModel.BiasInputWeight = weight.BW
|
||||
|
||||
weight, err = convertListCsvTo2dArr(outputWeightFileLines, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
elmModel.OutputWeight = weight.W
|
||||
|
||||
return &elmModel, nil
|
||||
}
|
||||
|
||||
func convertListCsvTo2dArr(input []string, useBias bool) (Weight, error) {
|
||||
var weight Weight
|
||||
|
||||
listSize := len(input)
|
||||
if listSize == 0 {
|
||||
return weight, errors.New("empty input list")
|
||||
}
|
||||
|
||||
csvElementSize := len(strings.Split(input[0], ","))
|
||||
for _, line := range input {
|
||||
if len(strings.Split(line, ",")) != csvElementSize {
|
||||
return weight, errors.New("invalid CSV length")
|
||||
}
|
||||
}
|
||||
|
||||
weightData := make([][]float64, listSize)
|
||||
biasWeightData := make([][]float64, listSize)
|
||||
|
||||
for i, line := range input {
|
||||
splittedLine := strings.Split(line, ",")
|
||||
temp := make([]float64, len(splittedLine))
|
||||
for j, val := range splittedLine {
|
||||
temp[j], _ = strconv.ParseFloat(strings.TrimSpace(val), 64)
|
||||
}
|
||||
if useBias {
|
||||
weightData[i] = temp[:len(temp)-1]
|
||||
biasWeightData[i] = []float64{temp[len(temp)-1]}
|
||||
} else {
|
||||
weightData[i] = temp
|
||||
}
|
||||
}
|
||||
|
||||
weight.W = RealMatrix{Rows: listSize, Cols: len(weightData[0]), Data: weightData}
|
||||
weight.BW = RealMatrix{Rows: listSize, Cols: 1, Data: biasWeightData}
|
||||
|
||||
return weight, nil
|
||||
}
|
||||
@@ -1,255 +0,0 @@
|
||||
package classify
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type HRVFeature struct {
|
||||
F01_AVNN float64
|
||||
F02_SDNN float64
|
||||
F03_RMSSD float64
|
||||
F04_SDSD float64
|
||||
F05_NNx float64
|
||||
F06_PNNx float64
|
||||
F07_HRV_TRIANGULAR_IDX float64
|
||||
F08_SD1 float64
|
||||
F09_SD2 float64
|
||||
F10_SD1_SD2_RATIO float64
|
||||
F11_S float64
|
||||
F12_TP float64
|
||||
F13_pLF float64
|
||||
F14_pHF float64
|
||||
F15_LFHFratio float64
|
||||
F16_VLF float64
|
||||
F17_LF float64
|
||||
F18_HF float64
|
||||
}
|
||||
|
||||
func NewHRVFeature(rrIntervalSet RRIntervalSet) *HRVFeature {
|
||||
var hrv HRVFeature
|
||||
|
||||
rrIntervalValue := rrIntervalSet.RRIntervalValue
|
||||
rrIntervalsValueDiff := rrIntervalSet.RRIntervalsValueDiff
|
||||
|
||||
hrv.F01_AVNN = f01_AVNN(rrIntervalValue)
|
||||
hrv.F02_SDNN = f02_SDNN(rrIntervalValue)
|
||||
hrv.F03_RMSSD = f03_RMSSD(rrIntervalsValueDiff)
|
||||
hrv.F04_SDSD = f04_SDSD(rrIntervalsValueDiff)
|
||||
hrv.F05_NNx = f05_NNx(rrIntervalsValueDiff, 50)
|
||||
hrv.F06_PNNx = f06_PNNx(rrIntervalValue, hrv.F05_NNx)
|
||||
hrv.F07_HRV_TRIANGULAR_IDX = f07_HRV_TRIANGULAR_IDX(rrIntervalValue)
|
||||
hrv.F08_SD1 = f08_SD1(hrv.F04_SDSD)
|
||||
hrv.F09_SD2 = f09_SD2(hrv.F02_SDNN, hrv.F04_SDSD)
|
||||
hrv.F10_SD1_SD2_RATIO = f10_SD1_SD2_RATIO(hrv.F08_SD1, hrv.F09_SD2)
|
||||
hrv.F11_S = f11_S(hrv.F08_SD1, hrv.F09_SD2)
|
||||
|
||||
feature12To18 := f12_18(rrIntervalValue, 2)
|
||||
hrv.F12_TP = feature12To18.TP
|
||||
hrv.F13_pLF = feature12To18.pLF
|
||||
hrv.F14_pHF = feature12To18.pHF
|
||||
hrv.F15_LFHFratio = feature12To18.LFHFratio
|
||||
hrv.F16_VLF = feature12To18.VLF
|
||||
hrv.F17_LF = feature12To18.LF
|
||||
hrv.F18_HF = feature12To18.HF
|
||||
|
||||
return &hrv
|
||||
}
|
||||
|
||||
func f01_AVNN(rrIntervalValue []float64) float64 {
|
||||
return mean(rrIntervalValue)
|
||||
}
|
||||
|
||||
func f02_SDNN(rrIntervalValue []float64) float64 {
|
||||
return sampleStandardDeviation(rrIntervalValue)
|
||||
}
|
||||
|
||||
func f03_RMSSD(rrIntervalsValueDiff []float64) float64 {
|
||||
return math.Sqrt(mean(powList(rrIntervalsValueDiff, 2)))
|
||||
}
|
||||
|
||||
func f04_SDSD(rrIntervalsValueDiff []float64) float64 {
|
||||
return sampleStandardDeviation(rrIntervalsValueDiff)
|
||||
}
|
||||
|
||||
func f05_NNx(rrIntervalsValueDiff []float64, x float64) float64 {
|
||||
count := filterCount(mulList(rrIntervalsValueDiff, 1000), func(y float64) bool {
|
||||
return y > x
|
||||
})
|
||||
return float64(count)
|
||||
}
|
||||
|
||||
func f06_PNNx(rrIntervalValue []float64, NNx float64) float64 {
|
||||
return (NNx / (float64(len(rrIntervalValue)) - 1)) * 100
|
||||
}
|
||||
|
||||
func f07_HRV_TRIANGULAR_IDX(rrIntervalValue []float64) float64 {
|
||||
binSize := 7.812
|
||||
var tempRr []float64
|
||||
for _, val := range rrIntervalValue {
|
||||
tempRr = append(tempRr, val*1000)
|
||||
}
|
||||
|
||||
sort.Float64s(tempRr)
|
||||
maxVal := tempRr[len(tempRr)-1]
|
||||
minVal := tempRr[0]
|
||||
|
||||
binCount := math.Ceil((maxVal - minVal) / binSize)
|
||||
edges := make([]float64, int(binCount)+1)
|
||||
var Nds []float64
|
||||
edges[0] = minVal
|
||||
|
||||
for i := 1; i <= int(binCount); i++ {
|
||||
edges[i] = edges[i-1] + binSize
|
||||
var d float64
|
||||
for _, x := range tempRr {
|
||||
if x >= edges[i-1] && x < edges[i] {
|
||||
d++
|
||||
}
|
||||
}
|
||||
if d != 0 {
|
||||
Nds = append(Nds, d)
|
||||
}
|
||||
}
|
||||
|
||||
return max(Nds) / sum(Nds)
|
||||
}
|
||||
|
||||
func f08_SD1(sdsd float64) float64 {
|
||||
return math.Sqrt(math.Pow(sdsd, 2) / 2)
|
||||
}
|
||||
|
||||
func f09_SD2(sdnn, sdsd float64) float64 {
|
||||
return math.Sqrt(2*math.Pow(sdnn, 2) - math.Pow(sdsd, 2)/2)
|
||||
}
|
||||
|
||||
func f10_SD1_SD2_RATIO(sd1, sd2 float64) float64 {
|
||||
return sd1 / sd2
|
||||
}
|
||||
|
||||
func f11_S(sd1, sd2 float64) float64 {
|
||||
return math.Pi * sd1 * sd2
|
||||
}
|
||||
|
||||
func f12_18(rrIntervalValue []float64, Fs float64) Feature12To18 {
|
||||
var feature Feature12To18
|
||||
// Implement the logic for feature calculation
|
||||
return feature
|
||||
}
|
||||
|
||||
func filterF(YY []float64, f []float64, predicate func(float64) bool) []float64 {
|
||||
var result []float64
|
||||
for i, val := range f {
|
||||
if predicate(val) {
|
||||
result = append(result, YY[i])
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func nanzscore(input []float64) []float64 {
|
||||
m := nanmean(input)
|
||||
s := nanstd(input)
|
||||
|
||||
var z []float64
|
||||
for _, val := range input {
|
||||
z = append(z, (val-m)/s)
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
func nanmean(input []float64) float64 {
|
||||
return mean(input)
|
||||
}
|
||||
|
||||
func nanstd(input []float64) float64 {
|
||||
return populationStandardDeviation(input)
|
||||
}
|
||||
|
||||
type Feature12To18 struct {
|
||||
TP float64
|
||||
pLF float64
|
||||
pHF float64
|
||||
LFHFratio float64
|
||||
VLF float64
|
||||
LF float64
|
||||
HF float64
|
||||
}
|
||||
|
||||
type RRIntervalSet struct {
|
||||
RRIntervalValue []float64
|
||||
RRIntervalsValueDiff []float64
|
||||
}
|
||||
|
||||
func mean(arr []float64) float64 {
|
||||
sum := 0.0
|
||||
for _, val := range arr {
|
||||
sum += val
|
||||
}
|
||||
return sum / float64(len(arr))
|
||||
}
|
||||
|
||||
func sampleStandardDeviation(arr []float64) float64 {
|
||||
mean := mean(arr)
|
||||
variance := 0.0
|
||||
for _, val := range arr {
|
||||
variance += math.Pow(val-mean, 2)
|
||||
}
|
||||
return math.Sqrt(variance / float64(len(arr)-1))
|
||||
}
|
||||
|
||||
func powList(arr []float64, exp float64) []float64 {
|
||||
var result []float64
|
||||
for _, val := range arr {
|
||||
result = append(result, math.Pow(val, exp))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func filterCount(arr []float64, predicate func(float64) bool) int {
|
||||
count := 0
|
||||
for _, val := range arr {
|
||||
if predicate(val) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func sum(arr []float64) float64 {
|
||||
total := 0.0
|
||||
for _, val := range arr {
|
||||
total += val
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
func max(arr []float64) float64 {
|
||||
if len(arr) == 0 {
|
||||
return 0
|
||||
}
|
||||
max := arr[0]
|
||||
for _, val := range arr {
|
||||
if val > max {
|
||||
max = val
|
||||
}
|
||||
}
|
||||
return max
|
||||
}
|
||||
|
||||
func populationStandardDeviation(input []float64) float64 {
|
||||
meanVal := mean(input)
|
||||
variance := 0.0
|
||||
for _, val := range input {
|
||||
variance += math.Pow(val-meanVal, 2)
|
||||
}
|
||||
return math.Sqrt(variance / float64(len(input)))
|
||||
}
|
||||
|
||||
func mulList(input []float64, multiplier float64) []float64 {
|
||||
result := make([]float64, len(input))
|
||||
for i, val := range input {
|
||||
result[i] = val * multiplier
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/stanleydv12/gateway-classification/src/entity"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// SetupDatabase initializes and returns a *gorm.DB object representing a connection to the database.
|
||||
//
|
||||
// It reads the database configuration from the environment variables and establishes a connection to the database using the specified parameters.
|
||||
// The function automatically migrates the entity.SensorData struct to the database and returns the *gorm.DB object.
|
||||
func SetupDatabase() *gorm.DB {
|
||||
|
||||
var err error
|
||||
|
||||
errEnv := godotenv.Load(".env")
|
||||
|
||||
if errEnv != nil {
|
||||
log.Fatal("Error loading .env")
|
||||
}
|
||||
|
||||
host := os.Getenv("DSN_HOST")
|
||||
user := os.Getenv("DSN_USER")
|
||||
password := os.Getenv("DSN_PASSWORD")
|
||||
dbname := os.Getenv("DSN_DB_NAME")
|
||||
port := os.Getenv("DSN_PORT")
|
||||
sslMode := os.Getenv("SSL_MODE")
|
||||
timeZone := os.Getenv("TIMEZONE")
|
||||
|
||||
dsn :=
|
||||
"host=" + host +
|
||||
" user=" + user +
|
||||
" password=" + password +
|
||||
" dbname=" + dbname +
|
||||
" port=" + port +
|
||||
" sslmode=" + sslMode +
|
||||
" TimeZone=" + timeZone
|
||||
|
||||
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
log.Fatalf("Error connecting to the database: %v", err)
|
||||
}
|
||||
|
||||
err = AutoMigrateAllEntities(db)
|
||||
if err != nil {
|
||||
log.Fatalf("Error migrating entities: %v", err)
|
||||
}
|
||||
|
||||
// Seeding
|
||||
InsertTestData(db)
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
// AutoMigrateAllEntities migrates all entities to the database.
|
||||
func AutoMigrateAllEntities(db *gorm.DB) error {
|
||||
err := db.AutoMigrate(
|
||||
&entity.Doctor{},
|
||||
&entity.ECG{},
|
||||
&entity.Patient{},
|
||||
&entity.SleepData{},
|
||||
&entity.SleepStage{},
|
||||
&entity.SleepQuality{},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func InsertTestData(db *gorm.DB) {
|
||||
// Contoh data Doctor
|
||||
doctorData := entity.Doctor{
|
||||
FirstName: "John",
|
||||
LastName: "Doe",
|
||||
Gender: "Male",
|
||||
Email: "john.doe@example.com",
|
||||
PhoneNumber: "123456789",
|
||||
BirthRate: time.Date(1980, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
RegistrationDate: time.Now(),
|
||||
Address: "123 Main St, City",
|
||||
}
|
||||
|
||||
// Contoh data Patient
|
||||
patientData := entity.Patient{
|
||||
FirstName: "Alice",
|
||||
LastName: "Johnson",
|
||||
Gender: "Female",
|
||||
Email: "alice.johnson@example.com",
|
||||
PhoneNumber: "987654321",
|
||||
BirthDate: time.Date(1990, 5, 15, 0, 0, 0, 0, time.UTC),
|
||||
RegistrationDate: time.Now(),
|
||||
Address: "456 Oak St, Town",
|
||||
SensorToken: "sensortoken123",
|
||||
StartSleepTime: time.Now(),
|
||||
EndSleepTime: time.Now().Add(8 * time.Hour), // Contoh: tidur selama 8 jam
|
||||
}
|
||||
|
||||
// Sisipkan data ke database
|
||||
db.Create(&doctorData)
|
||||
db.Create(&patientData)
|
||||
|
||||
fmt.Println("Data inserted successfully.")
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Doctor represents the Doctor table
|
||||
type Doctor struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
FirstName string `json:"first_name,omitempty"`
|
||||
LastName string `json:"last_name,omitempty"`
|
||||
Gender string `json:"gender,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
PhoneNumber string `json:"phone_number,omitempty"`
|
||||
BirthRate time.Time `json:"birth_rate,omitempty"`
|
||||
RegistrationDate time.Time `json:"registration_date,omitempty"`
|
||||
Address string `json:"address,omitempty"`
|
||||
}
|
||||
|
||||
// Patient represents the Patient table
|
||||
type Patient struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
FirstName string `json:"first_name,omitempty"`
|
||||
LastName string `json:"last_name,omitempty"`
|
||||
Gender string `json:"gender,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
PhoneNumber string `json:"phone_number,omitempty"`
|
||||
BirthDate time.Time `json:"birth_date,omitempty"`
|
||||
RegistrationDate time.Time `json:"registration_date,omitempty"`
|
||||
Address string `json:"address,omitempty"`
|
||||
SensorToken string `json:"sensor_token,omitempty"`
|
||||
StartSleepTime time.Time `json:"start_sleep_time,omitempty"`
|
||||
EndSleepTime time.Time `json:"end_sleep_time,omitempty"`
|
||||
}
|
||||
|
||||
// SleepData represents the Sleep Data table
|
||||
type SleepData struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
PatientID uint `json:"patient_id,omitempty"`
|
||||
FirstECGID uint `json:"first_ecg_id,omitempty"`
|
||||
FirstSleepStageID uint `json:"first_sleep_stage_id,omitempty"`
|
||||
SleepQualityID uint `json:"sleep_quality_id,omitempty"`
|
||||
FirstInputTime time.Time `json:"first_input_time,omitempty"`
|
||||
LastInputTime time.Time `json:"last_input_time,omitempty"`
|
||||
}
|
||||
|
||||
// ECG represents the ECG table
|
||||
type ECG struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
ReferenceID uint `json:"reference_id,omitempty"`
|
||||
Value float64 `json:"value,omitempty"`
|
||||
InputTime time.Time `json:"input_time,omitempty"`
|
||||
}
|
||||
|
||||
// SleepStage represents the Sleep Stage table
|
||||
type SleepStage struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
ReferenceID uint `json:"reference_id,omitempty"`
|
||||
Value string `json:"value,omitempty"`
|
||||
Method string `json:"method,omitempty"`
|
||||
}
|
||||
|
||||
// SleepQuality represents the Sleep Quality table
|
||||
type SleepQuality struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Value string `json:"value,omitempty"`
|
||||
InBedDuration time.Time `json:"in_bed_duration,omitempty"`
|
||||
BeginToSleepTime time.Time `json:"begin_to_sleep_time,omitempty"`
|
||||
AwakeFromSleepTime time.Time `json:"awake_from_sleep_time,omitempty"`
|
||||
SleepEfficiency float64 `json:"sleep_efficiency,omitempty"`
|
||||
LightSleepDuration time.Time `json:"light_sleep_duration,omitempty"`
|
||||
DeepSleepDuration time.Time `json:"deep_sleep_duration,omitempty"`
|
||||
REMDuration time.Time `json:"rem_duration,omitempty"`
|
||||
AwakeDuration time.Time `json:"awake_duration,omitempty"`
|
||||
InputTime time.Time `json:"input_time,omitempty"`
|
||||
}
|
||||
@@ -1,353 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/stanleydv12/gateway-classification/src/entity"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var saveTimer *time.Timer
|
||||
|
||||
// HandleEvent handles the given event and data.
|
||||
//
|
||||
// Parameters:
|
||||
// - event: a string representing the event to be handled.
|
||||
// - data: an interface{} containing the data related to the event.
|
||||
//
|
||||
// Returns: None.
|
||||
func HandleEvent(event string, data interface{}) {
|
||||
switch event {
|
||||
case "save-data":
|
||||
sensorData, ok := convertToSensorData(data)
|
||||
if !ok {
|
||||
fmt.Println("HandleEvent: Failed to convert data to SensorData")
|
||||
return
|
||||
}
|
||||
SaveData(sensorData)
|
||||
default:
|
||||
fmt.Println("HandleEvent: unknown event")
|
||||
}
|
||||
}
|
||||
|
||||
// SaveData saves the provided data to the database if it meets certain conditions.
|
||||
//
|
||||
// The function takes in a data interface{} parameter, which should be of type entity.ECG.
|
||||
// It first checks if the data is of the correct type using type assertion.
|
||||
// If the data is not of type entity.ECG, the function prints an error message and returns.
|
||||
//
|
||||
// The function then parses the input timestamp of the data and checks if it is valid.
|
||||
// If there is an error in parsing the timestamp, the function prints an error message and returns.
|
||||
//
|
||||
// The function calculates the time difference between the current time and the input timestamp.
|
||||
// If the time difference is greater than 30 seconds, the function prints a message and returns.
|
||||
//
|
||||
// If the data is the first ECG for a patient, the function sets the ReferenceID to 0.
|
||||
// Otherwise, it retrieves the ReferenceID for the patient using the GetReferenceIDForPatient function.
|
||||
//
|
||||
// The function creates a new instance of entity.ECG with the updated ReferenceID and other attributes.
|
||||
//
|
||||
// The function then attempts to save the newSensorData to the database using the DB.Create function.
|
||||
// If there is an error in saving the data, the function prints an error message and returns.
|
||||
//
|
||||
// Finally, if the data is successfully saved to the database, the function prints a success message.
|
||||
func SaveData(data interface{}) {
|
||||
fmt.Println(data)
|
||||
sensorData, ok := data.(entity.ECG)
|
||||
if !ok {
|
||||
fmt.Println("SaveData: Invalid data format")
|
||||
return
|
||||
}
|
||||
|
||||
// Note: Inject input time with current time
|
||||
sensorData.InputTime = time.Now()
|
||||
currentTime := time.Now()
|
||||
|
||||
diff := currentTime.Sub(sensorData.InputTime)
|
||||
if diff.Seconds() > 30 {
|
||||
fmt.Println("SaveData: Data is older than 30 seconds, skipping save to DB")
|
||||
return
|
||||
}
|
||||
|
||||
if isFirstEcg := CheckIfFirstECG(sensorData); isFirstEcg {
|
||||
sensorData.ReferenceID = 0
|
||||
|
||||
newSensorData := entity.ECG{
|
||||
ReferenceID: sensorData.ReferenceID,
|
||||
Value: sensorData.Value,
|
||||
InputTime: sensorData.InputTime,
|
||||
}
|
||||
|
||||
err := DB.Create(&newSensorData).Error
|
||||
if err != nil {
|
||||
fmt.Println("SaveData: Failed to save data to DB:", err)
|
||||
return
|
||||
}
|
||||
|
||||
firstSensorData := entity.ECG{}
|
||||
DB.Select("id").First(&firstSensorData)
|
||||
|
||||
sleepData := entity.SleepData{
|
||||
ID: 1,
|
||||
PatientID: 1,
|
||||
FirstECGID: firstSensorData.ID,
|
||||
FirstInputTime: firstSensorData.InputTime,
|
||||
}
|
||||
|
||||
err = DB.Save(&sleepData).Error
|
||||
if err != nil {
|
||||
fmt.Println("SaveData: Failed to save sleep data to DB:", err)
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
sensorData.ReferenceID = GetReferenceIDForPatient(sensorData)
|
||||
|
||||
newSensorData := entity.ECG{
|
||||
ReferenceID: sensorData.ReferenceID,
|
||||
Value: sensorData.Value,
|
||||
InputTime: sensorData.InputTime,
|
||||
}
|
||||
|
||||
err := DB.Create(&newSensorData).Error
|
||||
if err != nil {
|
||||
fmt.Println("SaveData: Failed to save data to DB:", err)
|
||||
return
|
||||
}
|
||||
|
||||
sleepData := entity.SleepData{
|
||||
ID: 1,
|
||||
PatientID: 1,
|
||||
LastInputTime: sensorData.InputTime,
|
||||
}
|
||||
|
||||
err = DB.Save(&sleepData).Error
|
||||
if err != nil {
|
||||
fmt.Println("SaveData: Failed to save sleep data to DB:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the timer to 30 seconds
|
||||
if saveTimer == nil {
|
||||
saveTimer = time.NewTimer(30 * time.Second)
|
||||
} else {
|
||||
saveTimer.Reset(30 * time.Second)
|
||||
}
|
||||
|
||||
fmt.Println("SaveData: Data saved to DB")
|
||||
}
|
||||
|
||||
// convertToSensorData converts the given data to a SensorData object.
|
||||
//
|
||||
// data: The data to be converted.
|
||||
// Returns: The converted SensorData object and a boolean indicating if the conversion was successful.
|
||||
func convertToSensorData(data interface{}) (entity.ECG, bool) {
|
||||
var sensorData entity.ECG
|
||||
err := mapstructure.Decode(data, &sensorData)
|
||||
if err != nil {
|
||||
return entity.ECG{}, false
|
||||
}
|
||||
return sensorData, true
|
||||
}
|
||||
|
||||
var DB *gorm.DB
|
||||
|
||||
// SetDBInstance sets the global variable DB to the given *gorm.DB instance.
|
||||
//
|
||||
// db: the *gorm.DB instance to be set.
|
||||
func SetDBInstance(db *gorm.DB) {
|
||||
DB = db
|
||||
}
|
||||
|
||||
// CheckIfFirstECG checks if the given ECG sensor data is the first data recorded for a given date.
|
||||
//
|
||||
// It takes an ECG object as a parameter and returns a boolean value indicating whether the data is the first for that date.
|
||||
func CheckIfFirstECG(sensorData entity.ECG) bool {
|
||||
var count int64
|
||||
var lastData entity.ECG
|
||||
|
||||
// Check if data is empty
|
||||
DB.Model(&entity.ECG{}).Count(&count)
|
||||
if count == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check if the last data for reference_id is not empty
|
||||
DB.Order("input_time DESC").Where("reference_id = ?", sensorData.ReferenceID).First(&lastData)
|
||||
if lastData.ID != 0 {
|
||||
// Check if input_time is more than 30 seconds from the current time
|
||||
currentTime := time.Now()
|
||||
timeDiff := currentTime.Sub(lastData.InputTime)
|
||||
if timeDiff.Seconds() > 30 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// GetReferenceIDForPatient retrieves the reference ID for a patient based on the given ECG sensor data.
|
||||
//
|
||||
// It takes the following parameter:
|
||||
// - sensorData: an instance of the entity.ECG struct representing the ECG sensor data.
|
||||
//
|
||||
// It returns a uint representing the reference ID.
|
||||
func GetReferenceIDForPatient(sensorData entity.ECG) uint {
|
||||
var referenceID uint
|
||||
DB.Model(&entity.ECG{}).Where("DATE(input_time) = ?", sensorData.InputTime.Format("2006-01-02")).Select("id").Order("id ASC").First(&referenceID)
|
||||
return referenceID
|
||||
}
|
||||
|
||||
// StartTimer starts the timer for saving data to DB and calling classifyData
|
||||
func StartTimer() {
|
||||
saveTimer = time.NewTimer(30 * time.Second)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-saveTimer.C:
|
||||
classifyData()
|
||||
saveTimer.Reset(30 * time.Second)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
type PredictionResponse struct {
|
||||
Prediction string `json:"prediction"`
|
||||
}
|
||||
|
||||
func classifyData() {
|
||||
|
||||
var lastECG entity.ECG
|
||||
if err := DB.Order("input_time desc").First(&lastECG).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
fmt.Println("No ecg data found in the database")
|
||||
} else {
|
||||
log.Fatalf("Failed to get last ecg data: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
sleepData := entity.SleepData{
|
||||
ID: 1,
|
||||
LastInputTime: lastECG.InputTime,
|
||||
}
|
||||
if err := DB.Save(&sleepData).Error; err != nil {
|
||||
log.Fatalf("Failed to save sleep data: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Mengambil data ECG berdasarkan ID
|
||||
var ecgByID []entity.ECG
|
||||
if err := DB.Where("id = ?", lastECG.ReferenceID).Find(&ecgByID).Error; err != nil {
|
||||
log.Fatalf("Failed to get ECG data by ID: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Mengambil semua data ECG berdasarkan reference ID
|
||||
var ecgByReferenceID []entity.ECG
|
||||
if err := DB.Where("reference_id = ?", lastECG.ReferenceID).Find(&ecgByReferenceID).Error; err != nil {
|
||||
log.Fatalf("Failed to get ECG data by reference ID: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Combine data retrieved by ID and reference ID
|
||||
allECG := append(ecgByID, ecgByReferenceID...)
|
||||
|
||||
// Process data in batches of 10
|
||||
for i := 0; i < len(allECG); i += 10 {
|
||||
end := i + 10
|
||||
if end > len(allECG) {
|
||||
end = len(allECG)
|
||||
}
|
||||
|
||||
batch := allECG[i:end]
|
||||
|
||||
// Call the function to handle the API call for this batch
|
||||
prediction, err := predict(batch)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to make prediction: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
sleepStage := entity.SleepStage{
|
||||
ID: 1,
|
||||
ReferenceID: 0,
|
||||
Value: prediction.Prediction,
|
||||
}
|
||||
|
||||
err = DB.Save(&sleepStage).Error
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to save sleep stage: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
var sleepData entity.SleepData
|
||||
err = DB.Find(&sleepData, "id = ?", 1).First(&sleepData).Error
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to get sleep data: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
sleepData.FirstSleepStageID = sleepStage.ID
|
||||
} else {
|
||||
sleepStage := entity.SleepStage{
|
||||
ReferenceID: 1,
|
||||
Value: prediction.Prediction,
|
||||
}
|
||||
|
||||
err = DB.Save(&sleepStage).Error
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to save sleep stage: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predict(data []entity.ECG) (PredictionResponse, error) {
|
||||
extractedValues := make([]float64, len(data))
|
||||
|
||||
for i, ecg := range data {
|
||||
extractedValues[i] = ecg.Value
|
||||
}
|
||||
|
||||
// Convert the extracted data slice to JSON
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return PredictionResponse{}, err
|
||||
}
|
||||
|
||||
predictURL := os.Getenv("PREDICT_URL")
|
||||
if predictURL == "" {
|
||||
return PredictionResponse{}, fmt.Errorf("PREDICT_URL environment variable is not set")
|
||||
}
|
||||
|
||||
resp, err := http.Post(predictURL, "application/json", bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return PredictionResponse{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return PredictionResponse{}, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var predictionResponse PredictionResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&predictionResponse); err != nil {
|
||||
return PredictionResponse{}, err
|
||||
}
|
||||
|
||||
return predictionResponse, nil
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package mqtt
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/stanleydv12/gateway-classification/src/handler"
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
Event string `json:"event"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
var Client mqtt.Client
|
||||
|
||||
var messagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
|
||||
fmt.Printf("Message Received from [%s] : %s\n", msg.Topic(), msg.Payload())
|
||||
|
||||
var receivedMessage Message
|
||||
err := json.Unmarshal(msg.Payload(), &receivedMessage)
|
||||
if err != nil {
|
||||
fmt.Println("Error decoding message:", err)
|
||||
return
|
||||
}
|
||||
|
||||
handler.HandleEvent(receivedMessage.Event, receivedMessage.Data)
|
||||
}
|
||||
|
||||
var connectHandler mqtt.OnConnectHandler = func(client mqtt.Client) {
|
||||
fmt.Println("Connected")
|
||||
Sub(client)
|
||||
}
|
||||
|
||||
var onLostHandler mqtt.ConnectionLostHandler = func(client mqtt.Client, err error) {
|
||||
fmt.Printf("Connection lost : %v", err)
|
||||
}
|
||||
|
||||
// SetupMqtt sets up the MQTT connection.
|
||||
//
|
||||
// It loads the environment variables from the .env file.
|
||||
// It creates a new MQTT client options object and configures it with the
|
||||
// MQTT broker host, port, and client ID.
|
||||
// It sets the default publish handler, on connect handler, and connection lost
|
||||
// handler for the MQTT client options.
|
||||
// It creates a new MQTT client with the configured options.
|
||||
// It connects the MQTT client to the broker.
|
||||
// If there is an error during the connection, it panics.
|
||||
func SetupMqtt() {
|
||||
errEnv := godotenv.Load(".env")
|
||||
if errEnv != nil {
|
||||
log.Fatal("Error loading .env")
|
||||
}
|
||||
|
||||
broker := os.Getenv("MQTT_BROKER_HOST")
|
||||
port := os.Getenv("MQTT_BROKER_PORT")
|
||||
clientID := os.Getenv("MQTT_CLIENT_ID")
|
||||
|
||||
opts := mqtt.NewClientOptions()
|
||||
opts.AddBroker(fmt.Sprintf("ws://%s:%s", broker, port))
|
||||
opts.SetClientID(clientID)
|
||||
opts.SetDefaultPublishHandler(messagePubHandler)
|
||||
opts.SetOnConnectHandler(connectHandler)
|
||||
opts.SetConnectionLostHandler(onLostHandler)
|
||||
|
||||
Client = mqtt.NewClient(opts)
|
||||
|
||||
if token := Client.Connect(); token.Wait() && token.Error() != nil {
|
||||
panic(token.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Sub is a function that subscribes to an MQTT topic and prints a message.
|
||||
//
|
||||
// It takes a client of type mqtt.Client as a parameter.
|
||||
// It does not return any value.
|
||||
func Sub(client mqtt.Client) {
|
||||
topic := os.Getenv("MQTT_TOPIC")
|
||||
token := client.Subscribe(topic, 1, nil)
|
||||
token.Wait()
|
||||
fmt.Printf("Subscribed to topic %s\n", topic)
|
||||
}
|
||||
|
||||
// Pub publishes the given message to the MQTT topic.
|
||||
//
|
||||
// It takes a single parameter, msg, which is of type interface{}.
|
||||
// The function does not return any value.
|
||||
func Pub(msg interface{}) {
|
||||
topic := os.Getenv("MQTT_TOPIC")
|
||||
token := Client.Publish(topic, 1, false, msg)
|
||||
token.Wait()
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
module github.com/dije07/sqqs
|
||||
|
||||
go 1.21.3
|
||||
|
||||
require (
|
||||
github.com/eclipse/paho.mqtt.golang v1.4.3
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/lib/pq v1.10.9
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
)
|
||||
@@ -1,32 +0,0 @@
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik=
|
||||
github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
@@ -1,390 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
MQTT "github.com/eclipse/paho.mqtt.golang"
|
||||
)
|
||||
|
||||
// Define your MQTT broker address and port
|
||||
const (
|
||||
brokerAddress = "ws://localhost:9001" // Change this to your MQTT broker address
|
||||
host = "localhost"
|
||||
port = 5432
|
||||
user = "postgres"
|
||||
password = "postgres"
|
||||
dbname = "sleep_monitoring"
|
||||
)
|
||||
|
||||
var DB *sql.DB
|
||||
|
||||
type Message struct {
|
||||
Event string `json:"event"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
type SleepQuality struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Value string `json:"value,omitempty"`
|
||||
DeepSleepDuration float64 `json:"deep_sleep_duration,omitempty"`
|
||||
AwakeDuration float64 `json:"awake_duration,omitempty"`
|
||||
TotalSleepDuration float64 `json:"total_sleep_duration,omitempty"`
|
||||
InputTime time.Time `json:"input_time,omitempty"`
|
||||
UserId uint `json:"user_id,omitempty"`
|
||||
}
|
||||
|
||||
// FuzzySet represents a fuzzy set with a membership function.
|
||||
type FuzzySet struct {
|
||||
Name string
|
||||
Terms map[string]func(float64) float64
|
||||
}
|
||||
|
||||
// Fuzzify function calculates the membership values for each term in the fuzzy set.
|
||||
func (fs *FuzzySet) Fuzzify(value float64) string {
|
||||
max := 0.0
|
||||
result := ""
|
||||
|
||||
for term, mf := range fs.Terms {
|
||||
membership := mf(value)
|
||||
if membership > max {
|
||||
max = membership
|
||||
result = term
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ApplyRule function evaluates the conditions and returns the corresponding action.
|
||||
func ApplyRule(conditions map[string]float64) (string, bool) {
|
||||
// Apply all rules
|
||||
switch {
|
||||
case conditions["awakeDuration"] == 1 && conditions["deepSleepTime"] == 1 && conditions["totalSleepTime"] == 1:
|
||||
return "LEVEL 9", true
|
||||
case conditions["awakeDuration"] == 1 && conditions["deepSleepTime"] == 1 && conditions["totalSleepTime"] == 0.5:
|
||||
return "LEVEL 8", true
|
||||
case conditions["awakeDuration"] == 1 && conditions["deepSleepTime"] == 1 && conditions["totalSleepTime"] == 0:
|
||||
return "LEVEL 7", true
|
||||
case conditions["awakeDuration"] == 1 && conditions["deepSleepTime"] == 0.5 && conditions["totalSleepTime"] == 1:
|
||||
return "LEVEL 7", true
|
||||
case conditions["awakeDuration"] == 1 && conditions["deepSleepTime"] == 0.5 && conditions["totalSleepTime"] == 0.5:
|
||||
return "LEVEL 6", true
|
||||
case conditions["awakeDuration"] == 1 && conditions["deepSleepTime"] == 0.5 && conditions["totalSleepTime"] == 0:
|
||||
return "LEVEL 5", true
|
||||
case conditions["awakeDuration"] == 1 && conditions["deepSleepTime"] == 0 && conditions["totalSleepTime"] == 1:
|
||||
return "LEVEL 5", true
|
||||
case conditions["awakeDuration"] == 1 && conditions["deepSleepTime"] == 0 && conditions["totalSleepTime"] == 0.5:
|
||||
return "LEVEL 4", true
|
||||
case conditions["awakeDuration"] == 1 && conditions["deepSleepTime"] == 0 && conditions["totalSleepTime"] == 0:
|
||||
return "LEVEL 3", true
|
||||
case conditions["awakeDuration"] == 0.5 && conditions["deepSleepTime"] == 1 && conditions["totalSleepTime"] == 1:
|
||||
return "LEVEL 8", true
|
||||
case conditions["awakeDuration"] == 0.5 && conditions["deepSleepTime"] == 1 && conditions["totalSleepTime"] == 0.5:
|
||||
return "LEVEL 7", true
|
||||
case conditions["awakeDuration"] == 0.5 && conditions["deepSleepTime"] == 1 && conditions["totalSleepTime"] == 0:
|
||||
return "LEVEL 6", true
|
||||
case conditions["awakeDuration"] == 0.5 && conditions["deepSleepTime"] == 0.5 && conditions["totalSleepTime"] == 1:
|
||||
return "LEVEL 6", true
|
||||
case conditions["awakeDuration"] == 0.5 && conditions["deepSleepTime"] == 0.5 && conditions["totalSleepTime"] == 0.5:
|
||||
return "LEVEL 5", true
|
||||
case conditions["awakeDuration"] == 0.5 && conditions["deepSleepTime"] == 0.5 && conditions["totalSleepTime"] == 0:
|
||||
return "LEVEL 4", true
|
||||
case conditions["awakeDuration"] == 0.5 && conditions["deepSleepTime"] == 0 && conditions["totalSleepTime"] == 1:
|
||||
return "LEVEL 4", true
|
||||
case conditions["awakeDuration"] == 0.5 && conditions["deepSleepTime"] == 0 && conditions["totalSleepTime"] == 0.5:
|
||||
return "LEVEL 3", true
|
||||
case conditions["awakeDuration"] == 0.5 && conditions["deepSleepTime"] == 0 && conditions["totalSleepTime"] == 0:
|
||||
return "LEVEL 2", true
|
||||
case conditions["awakeDuration"] == 0 && conditions["deepSleepTime"] == 1 && conditions["totalSleepTime"] == 1:
|
||||
return "LEVEL 7", true
|
||||
case conditions["awakeDuration"] == 0 && conditions["deepSleepTime"] == 1 && conditions["totalSleepTime"] == 0.5:
|
||||
return "LEVEL 6", true
|
||||
case conditions["awakeDuration"] == 0 && conditions["deepSleepTime"] == 1 && conditions["totalSleepTime"] == 0:
|
||||
return "LEVEL 5", true
|
||||
case conditions["awakeDuration"] == 0 && conditions["deepSleepTime"] == 0.5 && conditions["totalSleepTime"] == 1:
|
||||
return "LEVEL 5", true
|
||||
case conditions["awakeDuration"] == 0 && conditions["deepSleepTime"] == 0.5 && conditions["totalSleepTime"] == 0.5:
|
||||
return "LEVEL 4", true
|
||||
case conditions["awakeDuration"] == 0 && conditions["deepSleepTime"] == 0.5 && conditions["totalSleepTime"] == 0:
|
||||
return "LEVEL 3", true
|
||||
case conditions["awakeDuration"] == 0 && conditions["deepSleepTime"] == 0 && conditions["totalSleepTime"] == 1:
|
||||
return "LEVEL 3", true
|
||||
case conditions["awakeDuration"] == 0 && conditions["deepSleepTime"] == 0 && conditions["totalSleepTime"] == 0.5:
|
||||
return "LEVEL 2", true
|
||||
case conditions["awakeDuration"] == 0 && conditions["deepSleepTime"] == 0 && conditions["totalSleepTime"] == 0:
|
||||
return "LEVEL 1", true
|
||||
}
|
||||
|
||||
// No rule matched
|
||||
return "", false
|
||||
}
|
||||
|
||||
var messagePubHandler MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
|
||||
fmt.Printf("Message Received from [%s] : %s\n", msg.Topic(), msg.Payload())
|
||||
|
||||
if string(msg.Payload()) == "sleepStageReady" {
|
||||
quantifyData()
|
||||
}
|
||||
}
|
||||
|
||||
func setUpDB() *sql.DB {
|
||||
// Construct the connection string
|
||||
connStr := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
|
||||
os.Getenv("DB_HOST"), os.Getenv("DB_PORT"),
|
||||
os.Getenv("DB_USER"), os.Getenv("DB_PASSWORD"),
|
||||
os.Getenv("DB_NAME"))
|
||||
|
||||
// Open a connection to the database
|
||||
db, err := sql.Open("postgres", connStr)
|
||||
if err != nil {
|
||||
log.Fatal("Error connecting to the database: ", err)
|
||||
}
|
||||
|
||||
// Attempt to ping the database to verify connection
|
||||
err = db.Ping()
|
||||
if err != nil {
|
||||
log.Fatal("Error pinging the database: ", err)
|
||||
}
|
||||
|
||||
fmt.Println("Successfully connected to the database!")
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
var red *redis.Client
|
||||
|
||||
func quantifyData() {
|
||||
|
||||
var awake float64 = 0
|
||||
var deepSleep float64 = 0
|
||||
var totalSleep float64 = 0
|
||||
|
||||
db := setUpDB()
|
||||
DB = db
|
||||
value, err := red.Get(red.Context(), "sleep-stages").Result()
|
||||
if value == "" || err != nil {
|
||||
// Example query
|
||||
start := time.Now().UnixMilli()
|
||||
rows, err := DB.Query("SELECT * FROM sleep_stages")
|
||||
end := time.Now().UnixMilli()
|
||||
fmt.Println("Start : ", start)
|
||||
fmt.Println("End : ", end)
|
||||
fmt.Println("Duration : ", end-start, "ms")
|
||||
if err != nil {
|
||||
log.Fatal("Error querying the database: ", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
// Iterate over the rows
|
||||
for rows.Next() {
|
||||
var id int
|
||||
var reference_id string
|
||||
var value string
|
||||
var method any
|
||||
var timestamp time.Time
|
||||
err := rows.Scan(&id, &reference_id, &value, &method, ×tamp)
|
||||
if err != nil {
|
||||
log.Println("Error scanning row: ", err)
|
||||
}
|
||||
if value == "N1" || value == "N2" || value == "REM" {
|
||||
totalSleep++
|
||||
}
|
||||
if value == "N3" {
|
||||
totalSleep++
|
||||
deepSleep++
|
||||
}
|
||||
if value == "AWAKE" {
|
||||
awake++
|
||||
}
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
log.Println("Error iterating over rows: ", err)
|
||||
}
|
||||
} else {
|
||||
type SleepStage struct {
|
||||
ID uint `json:"id"`
|
||||
ReferenceID uint `json:"reference_id"`
|
||||
Value string `json:"value"`
|
||||
Method string `json:"method"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
type SleepStages struct {
|
||||
Stages []SleepStage `json:"sleep-stages"`
|
||||
}
|
||||
|
||||
// Unmarshal the JSON into a SleepStages struct
|
||||
var stages SleepStages
|
||||
err := json.Unmarshal([]byte(value), &stages)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
// Loop through the stages and print values
|
||||
for _, stage := range stages.Stages {
|
||||
if stage.Value == "N1" || stage.Value == "N2" || stage.Value == "REM" {
|
||||
totalSleep++
|
||||
}
|
||||
if stage.Value == "N3" {
|
||||
totalSleep++
|
||||
deepSleep++
|
||||
}
|
||||
if stage.Value == "AWAKE" {
|
||||
awake++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Define fuzzy sets and input values
|
||||
awakeDurationSet := FuzzySet{
|
||||
Name: "awakeDuration",
|
||||
Terms: map[string]func(float64) float64{
|
||||
"low": func(x float64) float64 { return math.Max(0, 1.0-0.5*x) },
|
||||
"medium": func(x float64) float64 { return math.Max(0, 1-2*math.Abs(x-0.5)) },
|
||||
"high": func(x float64) float64 { return math.Max(0, 2*x-1) },
|
||||
},
|
||||
}
|
||||
deepSleepDurationSet := FuzzySet{
|
||||
Name: "awakeDuration",
|
||||
Terms: map[string]func(float64) float64{
|
||||
"low": func(x float64) float64 { return math.Max(0, 1.0-0.5*x) },
|
||||
"medium": func(x float64) float64 { return math.Max(0, 1-2*math.Abs(x-0.5)) },
|
||||
"high": func(x float64) float64 { return math.Max(0, 2*x-1) },
|
||||
},
|
||||
}
|
||||
totalSleepDurationSet := FuzzySet{
|
||||
Name: "awakeDuration",
|
||||
Terms: map[string]func(float64) float64{
|
||||
"low": func(x float64) float64 { return math.Max(0, 1.0-0.5*x) },
|
||||
"medium": func(x float64) float64 { return math.Max(0, 1-2*math.Abs(x-0.5)) },
|
||||
"high": func(x float64) float64 { return math.Max(0, 2*x-1) },
|
||||
},
|
||||
}
|
||||
|
||||
inputValues := map[string]float64{
|
||||
"awakeDuration": awake / 60,
|
||||
"deepSleepTime": deepSleep / 60,
|
||||
"totalSleepTime": totalSleep / 60,
|
||||
}
|
||||
|
||||
// Fuzzify the sleep data
|
||||
awakeTerm := awakeDurationSet.Fuzzify(inputValues["awakeDuration"])
|
||||
deepSleepTerm := deepSleepDurationSet.Fuzzify(inputValues["deepSleepTime"])
|
||||
totalSleepTerm := totalSleepDurationSet.Fuzzify(inputValues["totalSleepTime"])
|
||||
// Fuzzify the other sleep data...
|
||||
|
||||
// Print the intermediate results
|
||||
fmt.Println("Fuzzy Conditions:")
|
||||
fmt.Printf("Awake Duration: %s (%f)\n", awakeTerm, inputValues["awakeDuration"])
|
||||
fmt.Printf("Deep Sleep Duration: %s (%f)\n", deepSleepTerm, inputValues["deepSleepTime"])
|
||||
fmt.Printf("Total Sleep Duration: %s (%f)\n", totalSleepTerm, inputValues["totalSleepTime"])
|
||||
// Print the other fuzzy conditions...
|
||||
|
||||
// Map the linguistic terms to their respective numerical values
|
||||
linguisticValues := map[string]float64{
|
||||
"high": 1.0,
|
||||
"medium": 0.5,
|
||||
"low": 0.0,
|
||||
}
|
||||
|
||||
// Create a map for all conditions
|
||||
allConditions := map[string]float64{
|
||||
"awakeDuration": linguisticValues[awakeTerm],
|
||||
"deepSleepTime": linguisticValues[deepSleepTerm],
|
||||
"totalSleepTime": linguisticValues[totalSleepTerm],
|
||||
}
|
||||
|
||||
action, ruleMatched := ApplyRule(allConditions)
|
||||
|
||||
// Print the final results
|
||||
if ruleMatched {
|
||||
fmt.Println("\nRule Matched! Action:", action)
|
||||
} else {
|
||||
fmt.Println("\nNo Rule Matched.")
|
||||
}
|
||||
|
||||
sleepQuality := SleepQuality{
|
||||
Value: action,
|
||||
DeepSleepDuration: inputValues["deepSleepTime"],
|
||||
TotalSleepDuration: inputValues["totalSleepTime"],
|
||||
AwakeDuration: inputValues["awakeDuration"],
|
||||
InputTime: time.Now(),
|
||||
UserId: 1,
|
||||
}
|
||||
|
||||
sleepQualityJSON, err := json.Marshal(sleepQuality)
|
||||
if err != nil {
|
||||
fmt.Println("Error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
err = red.Set(red.Context(), "sleep_quality_1", sleepQualityJSON, 0).Err()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to save to redis: %v", err)
|
||||
} else {
|
||||
fmt.Println("Saved to redis")
|
||||
}
|
||||
|
||||
// Prepare the SQL statement for inserting data.
|
||||
stmt, err := db.Prepare("INSERT INTO sleep_qualities (value, deep_sleep_duration, awake_duration, total_sleep_duration, input_time, user_id) VALUES ($1, $2, $3, $4, $5, $6)")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
// Example data to be inserted.
|
||||
value1 := action
|
||||
value2 := inputValues["deepSleepTime"]
|
||||
value3 := inputValues["awakeDuration"]
|
||||
value4 := inputValues["totalSleepTime"]
|
||||
value5 := time.Now()
|
||||
value6 := 1
|
||||
|
||||
// Execute the SQL statement with the provided values.
|
||||
_, err = stmt.Exec(value1, value2, value3, value4, value5, value6)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
red = redis.NewClient(&redis.Options{
|
||||
Addr: os.Getenv("REDIS_ADDR"), // Redis server address
|
||||
Password: "", // no password set
|
||||
DB: 0, // use default DB
|
||||
})
|
||||
|
||||
// Set MQTT client options
|
||||
|
||||
opts := MQTT.NewClientOptions().AddBroker("ws://" + os.Getenv("MQTT_BROKER"))
|
||||
opts.SetClientID("MQTT_simulator")
|
||||
opts.SetDefaultPublishHandler(messagePubHandler)
|
||||
|
||||
topic := "sleep_monitoring"
|
||||
|
||||
// Create and start a client using the above options
|
||||
client := MQTT.NewClient(opts)
|
||||
if token := client.Connect(); token.Wait() && token.Error() != nil {
|
||||
fmt.Println("Error connecting to MQTT broker:", token.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Subscribe to MQTT topics
|
||||
if token := client.Subscribe(topic, 0, messagePubHandler); token.Wait() && token.Error() != nil {
|
||||
fmt.Println("Error subscribing to MQTT topic:", token.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Subscribed to topic: %s\n", topic)
|
||||
// Keep the program running indefinitely
|
||||
select {}
|
||||
}
|
||||
Reference in New Issue
Block a user