diff --git a/.gitignore b/.gitignore index ad6177e..05da85a 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ web/dist/ web/build/ web/.svelte-kit/ web/package-lock.json +cmd/server/web # Logs *.log \ No newline at end of file diff --git a/Makefile b/Makefile index 7987522..31dd268 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ frontend: ## backend: Build le backend Go backend: frontend @echo "Building Go binary..." - cd $(BACKEND_DIR) && go build -ldflags -H=windowsgui . + cd $(BACKEND_DIR) && go build -o ../../SMaster.exe -ldflags -H=windowsgui . @echo "Backend built successfully" ## build: Build complet (frontend + backend) diff --git a/cmd/server/icon.ico b/cmd/server/icon.ico new file mode 100644 index 0000000..db5da39 Binary files /dev/null and b/cmd/server/icon.ico differ diff --git a/cmd/server/main.go b/cmd/server/main.go index 89c502e..f43f342 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -44,8 +44,11 @@ func main() { log.Fatalf("Failed to start device manager: %v", err) } + // Channel de shutdown partagé entre main et le handler API + shutdownChan := make(chan struct{}) + // Create HTTP server with embedded files - server := api.NewServer(deviceManager, hub, cfg) + server := api.NewServer(deviceManager, hub, cfg, shutdownChan) mux := server.SetupRoutes() // Serve embedded static files @@ -76,12 +79,17 @@ func main() { } }() - // Wait for interrupt signal + // Wait for interrupt signal or API shutdown request quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) - <-quit - log.Println("Shutting down server...") + select { + case <-quit: + log.Println("Signal received, shutting down...") + case <-shutdownChan: + log.Println("API shutdown requested, shutting down...") + } + deviceManager.Stop() log.Println("Server stopped") } diff --git a/cmd/server/resource.syso b/cmd/server/resource.syso new file mode 100644 index 0000000..0c8ce8b Binary files /dev/null and b/cmd/server/resource.syso differ diff --git a/cmd/server/web/dist/index.html b/cmd/server/web/dist/index.html index c9ae829..5bde79d 100644 --- a/cmd/server/web/dist/index.html +++ b/cmd/server/web/dist/index.html @@ -7,8 +7,9 @@ - - + + +
diff --git a/internal/api/handlers.go b/internal/api/handlers.go index 08a4aee..c834a17 100644 --- a/internal/api/handlers.go +++ b/internal/api/handlers.go @@ -5,6 +5,7 @@ import ( "log" "net/http" "strconv" + "time" "git.rouggy.com/rouggy/ShackMaster/internal/config" "github.com/gorilla/websocket" @@ -15,13 +16,15 @@ type Server struct { hub *Hub config *config.Config upgrader websocket.Upgrader + shutdownChan chan struct{} } -func NewServer(dm *DeviceManager, hub *Hub, cfg *config.Config) *Server { +func NewServer(dm *DeviceManager, hub *Hub, cfg *config.Config, shutdownChan chan struct{}) *Server { return &Server{ deviceManager: dm, hub: hub, config: cfg, + shutdownChan: shutdownChan, upgrader: websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, @@ -74,6 +77,9 @@ func (s *Server) SetupRoutes() *http.ServeMux { mux.HandleFunc("/api/power/fanmode", s.handlePowerFanMode) mux.HandleFunc("/api/power/operate", s.handlePowerOperate) + // Shutdown endpoint + mux.HandleFunc("/api/shutdown", s.handleShutdown) + // Note: Static files are now served from embedded FS in main.go return mux @@ -510,6 +516,21 @@ func (s *Server) handleUltrabeamDirection(w http.ResponseWriter, r *http.Request s.sendJSON(w, map[string]string{"status": "ok"}) } +func (s *Server) handleShutdown(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + s.sendJSON(w, map[string]string{"status": "shutting down"}) + + go func() { + time.Sleep(200 * time.Millisecond) + log.Println("Shutdown requested via API") + close(s.shutdownChan) + }() +} + func (s *Server) sendJSON(w http.ResponseWriter, data interface{}) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(data) diff --git a/internal/services/weather/weather.go b/internal/services/weather/weather.go index d3797e1..6d68411 100644 --- a/internal/services/weather/weather.go +++ b/internal/services/weather/weather.go @@ -101,13 +101,14 @@ func (c *Client) GetWeatherData() (*WeatherData, error) { } // Convert to our structure + // OWM retourne wind_speed et gust en m/s — conversion en km/h weatherData := &WeatherData{ Temperature: owmData.Main.Temp, FeelsLike: owmData.Main.FeelsLike, Humidity: owmData.Main.Humidity, Pressure: owmData.Main.Pressure, - WindSpeed: owmData.Wind.Speed, - WindGust: owmData.Wind.Gust, + WindSpeed: owmData.Wind.Speed * 3.6, + WindGust: owmData.Wind.Gust * 3.6, WindDeg: owmData.Wind.Deg, Clouds: owmData.Clouds.All, UpdatedAt: time.Unix(owmData.Dt, 0).Format(time.RFC3339), diff --git a/web/popup.html b/web/popup.html new file mode 100644 index 0000000..c8a4b2b --- /dev/null +++ b/web/popup.html @@ -0,0 +1,16 @@ + + + + + +