mirror of
https://github.com/UbiquitousIntelligentSystemBINUS/SleepMonitoringSystemUsingEdgeCache.git
synced 2026-07-10 07:23:33 +07:00
391 lines
13 KiB
Go
391 lines
13 KiB
Go
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 {}
|
|
}
|