parent
207971f2db
commit
ea30512e65
|
|
@ -13,3 +13,7 @@ SessionGCMaxLifetime = 3600
|
|||
SessionHashFunc = sha1
|
||||
SessionHashKey = chucknorriswillkickyourassandeatyoursoul
|
||||
SessionCookieLifeTime = 3600
|
||||
|
||||
JID = test@kingpenguin.tk
|
||||
PWD = test
|
||||
PORT = 5222
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ var (
|
|||
)
|
||||
|
||||
func init() {
|
||||
log.SetLogger("console", "")
|
||||
log.SetLogger(variables.LogType, variables.LogParams)
|
||||
}
|
||||
|
||||
type SensorPrint struct {
|
||||
|
|
|
|||
|
|
@ -102,9 +102,7 @@ func (c *CommandRelayController) Prepare() {
|
|||
func (c *CommandRelayController) Post() {
|
||||
mac := c.Ctx.Input.Param(":sensor")
|
||||
r := relay.GetRelayByMac(mac)
|
||||
if r.Id != 0 {
|
||||
httplib.Get("http://"+r.IpAddress+"/toggle").SetTimeout(3*time.Second, 3*time.Second).String()
|
||||
}
|
||||
r.Toggle()
|
||||
|
||||
c.Ctx.Output.Body([]byte(""))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ import (
|
|||
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/teleinfo"
|
||||
|
||||
"html/template"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
//——————————————————————————————————————————————————————————————————————————————
|
||||
|
|
@ -57,12 +60,48 @@ func (c *ViewTeleinfoController) Get() {
|
|||
c.Data["isCompteurSelected"] = true
|
||||
c.Data["dataCompteur"] = teleinfo.GetLastDataForCompteur(cpt.AdresseCompteur)
|
||||
c.Data["compteurAdresse"] = cpt.AdresseCompteur
|
||||
if cpt.Description != "" {
|
||||
c.Data["compteurDescription"] = cpt.Description
|
||||
} else {
|
||||
c.Data["compteurDescription"] = cpt.AdresseCompteur
|
||||
desc := cpt.Description
|
||||
if desc == "" {
|
||||
desc = cpt.AdresseCompteur
|
||||
}
|
||||
c.Data["compteurDescription"] = desc
|
||||
dataPower := formatDataSensorTeleInfo(teleinfo.GetAllDataForCompteur(cpt.AdresseCompteur))
|
||||
c.Data["dataPower"] = template.JS(dataPower)
|
||||
}
|
||||
|
||||
c.TplNames = "teleinfo.tpl"
|
||||
}
|
||||
|
||||
|
||||
func formatDataSensorTeleInfo(values []teleinfo.TeleinfoTable) string {
|
||||
ret := ""
|
||||
for a := 0; a < 2; a++ {
|
||||
ret += "{name : \""
|
||||
if a == 0 {
|
||||
ret += "Heure Pleines"
|
||||
} else {
|
||||
ret += "Heure Creuses"
|
||||
}
|
||||
ret += "\",marker : {enabled : true, radius : 3}, data : ["
|
||||
for i := 0; i < len(values); i++ {
|
||||
if i > 0 {
|
||||
ret += ","
|
||||
}
|
||||
// TODO faire la dérivé de la puissance pour avoir les variations plutot que l'évolution de la puissance
|
||||
horodate := strconv.FormatInt((values[i].HorodateGMT.Unix()+int64(timezoneOffset))*1000, 10)
|
||||
value := ""
|
||||
if a == 0 {
|
||||
value = strconv.FormatInt(values[i].HeurePleinne, 10)
|
||||
} else {
|
||||
value = strconv.FormatInt(values[i].HeureCreuse, 10)
|
||||
}
|
||||
ret += "[" + horodate + "," + value + "]"
|
||||
}
|
||||
ret += "]}"
|
||||
|
||||
if a == 0 {
|
||||
ret += ","
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/gorilla/websocket"
|
||||
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/watchlog"
|
||||
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
||||
|
||||
type WebSocketController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (c *WebSocketController) Prepare() {
|
||||
sess := c.GetSession(variables.SessionName)
|
||||
if sess == nil {
|
||||
c.Redirect(variables.LoginRouteNoRegex+variables.UserRoute, 302)
|
||||
} else {
|
||||
c.Data["IsAuthentificated"] = true
|
||||
}
|
||||
|
||||
c.Data["IsLog"] = true
|
||||
c.Data["version"] = variables.Version
|
||||
}
|
||||
|
||||
|
||||
// Get method handles GET requests for WebSocketController.
|
||||
func (c *WebSocketController) Get() {
|
||||
c.Data["hostWS"] = "ws://"+c.Ctx.Request.Host+variables.WebSocketLogRoute
|
||||
c.TplNames = "watchlog.tpl"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Join method handles WebSocket requests for WebSocketController.
|
||||
func (this *WebSocketController) Join() {
|
||||
// Upgrade from http request to WebSocket.
|
||||
ws, err := websocket.Upgrade(this.Ctx.ResponseWriter, this.Ctx.Request, nil, 1024, 1024)
|
||||
if _, ok := err.(websocket.HandshakeError); ok {
|
||||
http.Error(this.Ctx.ResponseWriter, "Not a websocket handshake", 400)
|
||||
return
|
||||
} else if err != nil {
|
||||
beego.Error("Cannot setup WebSocket connection:", err)
|
||||
return
|
||||
}
|
||||
|
||||
watchlog.ListWebSocket.PushFront(ws)
|
||||
|
||||
|
||||
// Message receive loop.
|
||||
for {
|
||||
_, _, err := ws.ReadMessage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
this.Ctx.Output.Body([]byte(""))
|
||||
}
|
||||
8
main.go
8
main.go
|
|
@ -5,6 +5,9 @@ import (
|
|||
_ "git.kingpenguin.tk/chteufleur/datahouse.git/models/temperature"
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/user"
|
||||
_ "git.kingpenguin.tk/chteufleur/datahouse.git/routers"
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/xmpp"
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/watchlog"
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/logs"
|
||||
|
|
@ -18,7 +21,7 @@ var (
|
|||
)
|
||||
|
||||
func init() {
|
||||
log.SetLogger("console", "")
|
||||
log.SetLogger(variables.LogType, variables.LogParams)
|
||||
url := ""
|
||||
db := ""
|
||||
if database.DatabaseInstance == database.MySQL {
|
||||
|
|
@ -51,6 +54,7 @@ func main() {
|
|||
if !user.IsUserExist("admin") {
|
||||
user.AddUser("admin", "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918")
|
||||
}
|
||||
|
||||
go xmpp_manager.Run()
|
||||
go watchlog.Run()
|
||||
beego.Run()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,12 @@ package relay
|
|||
|
||||
import (
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/astaxie/beego/httplib"
|
||||
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
|
||||
|
||||
"time"
|
||||
)
|
||||
|
||||
type RelayTable struct {
|
||||
|
|
@ -120,3 +123,11 @@ func DeleteSensor(id int64) {
|
|||
o.Using(database.Alias)
|
||||
o.Delete(&RelayTable{Id: id})
|
||||
}
|
||||
|
||||
func (relay *RelayTable) Toggle() (error) {
|
||||
var err error
|
||||
if relay.Id != 0 {
|
||||
_, err = httplib.Get("http://"+relay.IpAddress+"/toggle").SetTimeout(3*time.Second, 3*time.Second).String()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||
|
||||
"time"
|
||||
)
|
||||
|
|
@ -26,7 +27,7 @@ var (
|
|||
)
|
||||
|
||||
func init() {
|
||||
log.SetLogger("console", "")
|
||||
log.SetLogger(variables.LogType, variables.LogParams)
|
||||
orm.RegisterModel(new(TeleinfoTable), new(CompteurTeleinfoTable))
|
||||
orm.DefaultRowsLimit = 4500
|
||||
|
||||
|
|
@ -114,6 +115,11 @@ func GetLastDataForCompteur(adresseCompteur string) *TeleinfoTable {
|
|||
return data
|
||||
}
|
||||
|
||||
func DeleteDataCompteur(adresseCompteur string) {
|
||||
o := orm.NewOrm()
|
||||
o.Using(database.Alias)
|
||||
o.Delete(&TeleinfoTable{AdresseCompteur: adresseCompteur})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -220,10 +226,15 @@ func DeleteCompteurByAdresse(adresse string) {
|
|||
o := orm.NewOrm()
|
||||
o.Using(database.Alias)
|
||||
o.Delete(&CompteurTeleinfoTable{AdresseCompteur: adresse})
|
||||
|
||||
DeleteDataCompteur(adresse)
|
||||
}
|
||||
|
||||
func DeleteCompteur(compteurId int64) {
|
||||
compteur := GetSensor(compteurId)
|
||||
o := orm.NewOrm()
|
||||
o.Using(database.Alias)
|
||||
o.Delete(&CompteurTeleinfoTable{Id: compteurId})
|
||||
|
||||
DeleteDataCompteur(compteur.AdresseCompteur)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||
|
||||
"time"
|
||||
)
|
||||
|
|
@ -25,7 +26,7 @@ var (
|
|||
)
|
||||
|
||||
func init() {
|
||||
log.SetLogger("console", "")
|
||||
log.SetLogger(variables.LogType, variables.LogParams)
|
||||
orm.RegisterModel(new(TempTableTmp))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||
|
||||
"time"
|
||||
)
|
||||
|
|
@ -23,7 +24,7 @@ var (
|
|||
)
|
||||
|
||||
func init() {
|
||||
log.SetLogger("console", "")
|
||||
log.SetLogger(variables.LogType, variables.LogParams)
|
||||
orm.RegisterModel(new(TempTable))
|
||||
orm.DefaultRowsLimit = 4500
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,51 @@
|
|||
package variables
|
||||
|
||||
const (
|
||||
Version = "0.0.5.0"
|
||||
Version = "0.1.2"
|
||||
|
||||
SessionName = "Session_Data_House"
|
||||
|
||||
sensorMacRegex = ":sensor([0-9A-Fa-f:]+)"
|
||||
|
||||
logFile = "file"
|
||||
LogFileName = "filename"
|
||||
LogFilePath = "datahouse.log"
|
||||
logConsole = "console"
|
||||
)
|
||||
|
||||
var (
|
||||
RootRoute = "/"
|
||||
/*
|
||||
————————————————————————————————————————————————————————————————————————————————
|
||||
Routes
|
||||
————————————————————————————————————————————————————————————————————————————————
|
||||
*/
|
||||
RootRoute = "/"
|
||||
|
||||
AddTempRoute = "/add/temp/" + sensorMacRegex + "/:val([0-9]+)"
|
||||
AddRelayRoute = "/add/relay/" + sensorMacRegex
|
||||
TeleinfoAddRoute = "/teleinfo/add"
|
||||
AddTempRoute = "/add/temp/" + sensorMacRegex + "/:val([0-9]+)"
|
||||
AddRelayRoute = "/add/relay/" + sensorMacRegex
|
||||
TeleinfoAddRoute = "/teleinfo/add"
|
||||
|
||||
ViewTempRoute = "/view/temp"
|
||||
ViewRelaysRoute = "/view/relay"
|
||||
ViewRelayRoute = "/view/relay/" + sensorMacRegex
|
||||
ViewTeleinfosRoute = "/view/teleinfo"
|
||||
ViewTeleinfoRoute = "/view/teleinfo/:compteur([0-9A-Fa-f:]+)"
|
||||
ViewLogRoute = "/view/log"
|
||||
WebSocketLogRoute = "/view/log/join"
|
||||
|
||||
CommandRelayRoute = "/command/relay/" + sensorMacRegex
|
||||
CommandRelayRoute = "/command/relay/" + sensorMacRegex
|
||||
|
||||
SensorsRoute = "/sensors"
|
||||
LoginRoute = "/login/:route(.*)"
|
||||
LoginRouteNoRegex = "/login"
|
||||
UserRoute = "/user"
|
||||
SensorsRoute = "/sensors"
|
||||
LoginRoute = "/login/:route(.*)"
|
||||
LoginRouteNoRegex = "/login"
|
||||
UserRoute = "/user"
|
||||
|
||||
|
||||
/*
|
||||
————————————————————————————————————————————————————————————————————————————————
|
||||
Logs
|
||||
————————————————————————————————————————————————————————————————————————————————
|
||||
*/
|
||||
LogType = logFile
|
||||
LogParams = "{\""+LogFileName+"\":\""+LogFilePath+"\"}"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ func init() {
|
|||
beego.Router(variables.ViewTempRoute, &controllers.ViewTempController{})
|
||||
beego.Router(variables.ViewRelaysRoute, &controllers.ViewRelayController{})
|
||||
beego.Router(variables.ViewRelayRoute, &controllers.ViewRelayController{})
|
||||
beego.Router(variables.ViewLogRoute, &controllers.WebSocketController{})
|
||||
beego.Router(variables.WebSocketLogRoute, &controllers.WebSocketController{}, "get:Join")
|
||||
|
||||
beego.Router(variables.CommandRelayRoute, &controllers.CommandRelayController{})
|
||||
|
||||
|
|
@ -25,4 +27,5 @@ func init() {
|
|||
beego.Router(variables.SensorsRoute, &controllers.SensorsController{})
|
||||
beego.Router(variables.LoginRoute, &controllers.LoginController{})
|
||||
beego.Router(variables.UserRoute, &controllers.UserController{})
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,20 +4,25 @@
|
|||
* Version 1.0
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* TODO : Gestion du temps pour n'envoyer que toute les minutes (ou un truc du genre)
|
||||
*/
|
||||
#include <ESP8266WiFi.h>
|
||||
#define startFrame 0x02
|
||||
#define endFrame 0x03
|
||||
#define startLine 0x0A
|
||||
#define endLine 0x0D
|
||||
#define space 0x20
|
||||
|
||||
//----------------------------------------------------
|
||||
|
||||
/*
|
||||
const char* ssid = "TNCAP3F2E03";
|
||||
const char* password = "73ABCCAA87";
|
||||
*/
|
||||
const char* ssid = "L0AD";
|
||||
const char* password = "";
|
||||
|
||||
//const char* host = "datahouse.kingpenguin.tk";
|
||||
const char* host = "192.168.1.143";
|
||||
const int httpPort = 8080;
|
||||
|
||||
const char* host = "datahouse.kingpenguin.tk";
|
||||
const int httpPort = 80;
|
||||
const int DEFAULT_INTERVAL = 60000; // 60 sec
|
||||
|
||||
//----------------------------------------------------
|
||||
|
|
@ -37,7 +42,7 @@ void sleepSec(int sec) {
|
|||
|
||||
|
||||
|
||||
long nextInterval;
|
||||
long nextInterval = millis() + DEFAULT_INTERVAL;
|
||||
|
||||
void sendDataToServer() {
|
||||
// Use WiFiClient class to create TCP connections
|
||||
|
|
@ -46,18 +51,12 @@ void sendDataToServer() {
|
|||
Serial.print("connection failed on host ");
|
||||
Serial.print(host);
|
||||
Serial.print(":");
|
||||
Serial.println(host);
|
||||
Serial.println(httpPort);
|
||||
return;
|
||||
}
|
||||
|
||||
// We now create a URI for the request
|
||||
// TODO a finir
|
||||
String url = "/teleinfo/add?ADCO="+ADCO+"&OPTARIF="+OPTARIF+"&BASE="+BASE+"&HCHC="+HCHC+"&HCHP="+HCHP;
|
||||
ADCO = "";
|
||||
OPTARIF = "";
|
||||
BASE = "";
|
||||
HCHC = "";
|
||||
HCHP = "";
|
||||
|
||||
Serial.print("Requesting URL: ");
|
||||
Serial.println(url);
|
||||
|
|
@ -85,6 +84,19 @@ void sendDataToServer() {
|
|||
nextInterval = millis() + nextInterval;
|
||||
}
|
||||
|
||||
bool isDigitSelf(char c) {
|
||||
return c >= 48 && c <= 57;
|
||||
}
|
||||
|
||||
bool isNumberSelf(String s) {
|
||||
for (int i=0; i<(s.length()); i++){
|
||||
if (!isDigitSelf(s[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(1200);
|
||||
|
|
@ -110,48 +122,79 @@ void setup() {
|
|||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
String label = "";
|
||||
String value = "";
|
||||
char checksum = 0;
|
||||
|
||||
void GetTeleInfo() {
|
||||
String TeleInfo = "";
|
||||
char charIn = 0;
|
||||
|
||||
int index = 0; // 0 - label ; 1 - value ; 2 - checksum
|
||||
label = "";
|
||||
value = "";
|
||||
checksum = 0;
|
||||
|
||||
if (Serial.available() > 0) {
|
||||
while (charIn != startLine) {
|
||||
charIn = Serial.read() & 0x7F;
|
||||
}
|
||||
while (charIn != endLine) {
|
||||
// label
|
||||
if (Serial.available() > 0) {
|
||||
charIn = Serial.read() & 0x7F;
|
||||
if (charIn != space) {
|
||||
if (index == 0) {
|
||||
label += charIn;
|
||||
} else if (index == 1) {
|
||||
value += charIn;
|
||||
} else if (index == 2) {
|
||||
checksum = charIn;
|
||||
index++;
|
||||
}
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool checkSumVerif() {
|
||||
char sum=0;
|
||||
String trame = label + " " + value;
|
||||
for (int i=0; i<(trame.length()); i++){
|
||||
sum += trame[i];
|
||||
}
|
||||
sum = (sum & 0x3F) + 0x20;
|
||||
return sum == checksum;
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
if (Serial.available() > 0) {
|
||||
String str = Serial.readStringUntil('\n');
|
||||
GetTeleInfo();
|
||||
if (checkSumVerif()) {
|
||||
Serial.println(label+" "+value+" "+checksum);
|
||||
|
||||
if (label == "ADCO" && isNumberSelf(value)) {
|
||||
ADCO = value;
|
||||
}
|
||||
if (label == "OPTARIF") {
|
||||
OPTARIF = value;
|
||||
}
|
||||
if (label == "BASE") {
|
||||
BASE = value;
|
||||
}
|
||||
if (label == "HCHC" && isNumberSelf(value)) {
|
||||
HCHC = value;
|
||||
}
|
||||
if (label == "HCHP" && isNumberSelf(value)) {
|
||||
HCHP = value;
|
||||
}
|
||||
|
||||
if (millis() >= nextInterval) {
|
||||
bool sendable = false;
|
||||
|
||||
int i = str.indexOf("ADCO");
|
||||
if (i != -1) {
|
||||
i = i + 4 +1;
|
||||
ADCO = str.substring(i, i+12);
|
||||
}
|
||||
|
||||
i = str.indexOf("OPTARIF");
|
||||
if (i != -1) {
|
||||
i = i + 7 +1;
|
||||
OPTARIF = str.substring(i, i+4);
|
||||
}
|
||||
|
||||
i = str.indexOf("BASE");
|
||||
if (i != -1) {
|
||||
i = i + 4 +1;
|
||||
BASE = str.substring(i, i+9);
|
||||
}
|
||||
|
||||
i = str.indexOf("HCHC");
|
||||
if (i != -1) {
|
||||
i = i + 4 +1;
|
||||
HCHC = str.substring(i, i+9);
|
||||
}
|
||||
|
||||
i = str.indexOf("HCHP");
|
||||
if (i != -1) {
|
||||
i = i + 4 +1;
|
||||
HCHP = str.substring(i, i+9);
|
||||
sendable = true;
|
||||
}
|
||||
|
||||
|
||||
if (sendable && ADCO != "") {
|
||||
sendDataToServer();
|
||||
}
|
||||
sendDataToServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
{{if .IsViewTemp}}
|
||||
class="active"
|
||||
{{end}}
|
||||
><a href="/view/temp">Temperatures</a></li>
|
||||
><a href="/view/temp">Températures</a></li>
|
||||
|
||||
<li
|
||||
{{if .IsViewRelay}}
|
||||
|
|
@ -33,6 +33,11 @@
|
|||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
{{if .IsAuthentificated}}
|
||||
<li
|
||||
{{if .IsLog}}
|
||||
class="active"
|
||||
{{end}}
|
||||
><a href="/view/log">Logs</a></li>
|
||||
<li
|
||||
{{if .IsUser}}
|
||||
class="active"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,94 @@
|
|||
{{template "base/base.html" .}}
|
||||
{{define "meta"}}
|
||||
<script type="text/javascript" src="/static/js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="/static/highstock/js/highstock.js"></script>
|
||||
<script type="text/javascript" src="/static/highstock/js/themes/grid.js"></script>
|
||||
<script type="text/javascript" src="/static/highstock/js/modules/exporting.js"></script>
|
||||
<script src="http://code.highcharts.com/highcharts.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
chart1 = new Highcharts.StockChart({
|
||||
chart: {
|
||||
renderTo : 'graphe',
|
||||
load : function () {
|
||||
// set up the updating of the chart each second
|
||||
var series = this.series[0];
|
||||
setInterval(function () {
|
||||
var x = (new Date()).getTime(), // current time
|
||||
y = Math.round(Math.random() * 100);
|
||||
series.addPoint([x, y], true, true);
|
||||
}, 1000);
|
||||
}
|
||||
},
|
||||
rangeSelector: {
|
||||
buttons: [{
|
||||
count: 3,
|
||||
type: 'hour',
|
||||
text: '3h'
|
||||
},{
|
||||
count: 6,
|
||||
type: 'hour',
|
||||
text: '6h'
|
||||
},{
|
||||
count: 12,
|
||||
type: 'hour',
|
||||
text: '12h'
|
||||
}, {
|
||||
count: 1,
|
||||
type: 'day',
|
||||
text: '1j'
|
||||
}, {
|
||||
count: 2,
|
||||
type: 'day',
|
||||
text: '2j'
|
||||
}, {
|
||||
count: 3,
|
||||
type: 'day',
|
||||
text: '3j',
|
||||
}, {
|
||||
count: 5,
|
||||
type: 'day',
|
||||
text: '5j'
|
||||
}, {
|
||||
count: 7,
|
||||
type: 'day',
|
||||
text: '7j'
|
||||
}, {
|
||||
count: 1,
|
||||
type: 'month',
|
||||
text: '1m'
|
||||
}, {
|
||||
type: 'all',
|
||||
text: 'All'
|
||||
}],
|
||||
selected: 5
|
||||
},
|
||||
yAxis: {
|
||||
title: {
|
||||
text: 'Puissance (W)'
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'datetime'
|
||||
},
|
||||
scrollbar : {
|
||||
enabled : false
|
||||
},
|
||||
legend : {
|
||||
enabled : true,
|
||||
layout: 'vertical',
|
||||
verticalAlign : 'middle',
|
||||
align : 'right'
|
||||
},
|
||||
series : [ {{.dataPower}} ]
|
||||
});
|
||||
});
|
||||
Highcharts.setOptions({
|
||||
global: {
|
||||
useUTC: false
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{{end}}
|
||||
{{define "extrajs"}}
|
||||
{{end}}
|
||||
|
|
@ -54,6 +143,8 @@
|
|||
<h4>Option base: <small>{{.dataCompteur.OptionBase}}</small></h4>
|
||||
<h4>Heure pleine: <small>{{.dataCompteur.HeurePleinne}} Wh</small></h4>
|
||||
<h4>Heure creuse: <small>{{.dataCompteur.HeureCreuse}} Wh</small></h4>
|
||||
|
||||
<div style="margin-top: 30px;" id="graphe"></div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
{{template "base/base.html" .}}
|
||||
{{define "meta"}}
|
||||
{{end}}
|
||||
{{define "extrajs"}}
|
||||
<script>
|
||||
var logs = document.getElementById("log")
|
||||
var ws = new WebSocket("{{.hostWS}}");
|
||||
ws.onopen = function(evt) {
|
||||
}
|
||||
ws.onclose = function(evt) {
|
||||
ws = null;
|
||||
}
|
||||
ws.onmessage = function(evt) {
|
||||
log.innerHTML = evt.data + "\n" + logs.innerHTML;
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
||||
{{define "body"}}
|
||||
<textarea id="log" readonly="readonly" rows="20" style="width: 100%;">
|
||||
</textarea>
|
||||
{{end}}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package watchlog
|
||||
|
||||
import (
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/hpcloud/tail"
|
||||
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||
|
||||
"container/list"
|
||||
)
|
||||
|
||||
var (
|
||||
ListWebSocket = list.New()
|
||||
)
|
||||
|
||||
|
||||
func Run() {
|
||||
t, _ := tail.TailFile(variables.LogFilePath, tail.Config{Follow: true})
|
||||
for line := range t.Lines {
|
||||
broadcastWebSocket(line.Text)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func broadcastWebSocket(message string) {
|
||||
for sub := ListWebSocket.Front(); sub != nil; sub = sub.Next() {
|
||||
// Immediately send event to WebSocket users.
|
||||
ws := sub.Value.(*websocket.Conn)
|
||||
err := ws.WriteMessage(websocket.TextMessage, []byte(message))
|
||||
if err != nil {
|
||||
toRemove := sub
|
||||
sub = sub.Prev()
|
||||
ListWebSocket.Remove(toRemove)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
package xmpp_manager
|
||||
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/logs"
|
||||
|
||||
"git.kingpenguin.tk/chteufleur/go-xmpp.git"
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/relay"
|
||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||
|
||||
"time"
|
||||
)
|
||||
|
||||
|
||||
const (
|
||||
Status_online = ""
|
||||
Status_offline = ""
|
||||
Status_away = "away"
|
||||
Status_chat = "chat"
|
||||
Status_do_not_disturb = "dnd"
|
||||
Status_extended_away = "xa"
|
||||
|
||||
Type_available = ""
|
||||
Type_unavailable = "unavailable"
|
||||
Type_subscribe = "subscribe"
|
||||
Type_subscribed = "subscribed"
|
||||
Type_unsubscribe = "unsubscribe"
|
||||
Type_unsubscribed = "unsubscribed"
|
||||
Type_probe = "probe"
|
||||
Type_error = "error"
|
||||
)
|
||||
|
||||
var (
|
||||
log = logs.NewLogger(10000)
|
||||
|
||||
JidStr = beego.AppConfig.String("JID")
|
||||
passwdStr = beego.AppConfig.String("PWD")
|
||||
serverPort = beego.AppConfig.String("PORT")
|
||||
|
||||
jid xmpp.JID
|
||||
stream = new(xmpp.Stream)
|
||||
client = new(xmpp.XMPP)
|
||||
|
||||
Debug = false
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.SetLogger(variables.LogType, variables.LogParams)
|
||||
}
|
||||
|
||||
|
||||
func must(v interface{}, err error) interface{} {
|
||||
if err != nil {
|
||||
log.Error("Must error : ", err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func Run() {
|
||||
// Create stream and configure it as a component connection.
|
||||
jid = must(xmpp.ParseJID(JidStr)).(xmpp.JID)
|
||||
stream = must(xmpp.NewStream(jid.Domain+":"+serverPort, &xmpp.StreamConfig{LogStanzas: Debug})).(*xmpp.Stream)
|
||||
client = must(xmpp.NewClientXMPP(stream, jid, passwdStr, &xmpp.ClientConfig{InsecureSkipVerify: true})).(*xmpp.XMPP)
|
||||
|
||||
mainXMPP()
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
Run()
|
||||
}
|
||||
|
||||
|
||||
func mainXMPP() {
|
||||
SendPresence(Status_online, Type_available, "")
|
||||
|
||||
for x := range client.In {
|
||||
switch v := x.(type) {
|
||||
case *xmpp.Presence:
|
||||
|
||||
case *xmpp.Message:
|
||||
log.Info("Message received : %s", v.Body)
|
||||
|
||||
case *xmpp.Iq:
|
||||
// TODO check if the caller has privilege to ask
|
||||
switch v.PayloadName().Space {
|
||||
case xmpp.NsDiscoItems:
|
||||
execDiscoCommand(v)
|
||||
|
||||
case xmpp.NodeAdHocCommand:
|
||||
execCommandAdHoc(v)
|
||||
}
|
||||
|
||||
default:
|
||||
log.Info("recv: %v", x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func SendPresence(status, tpye, message string) {
|
||||
client.Out <- xmpp.Presence{From: jid.Domain, Show: status, Type: tpye, Status: message}
|
||||
}
|
||||
|
||||
|
||||
func execDiscoCommand(iq *xmpp.Iq) {
|
||||
log.Info("Discovery item iq received")
|
||||
reply := iq.Response(xmpp.IqTypeResult)
|
||||
discoItem := &xmpp.DiscoItems{Node: xmpp.NodeAdHocCommand}
|
||||
|
||||
relays := relay.GetAllRelay()
|
||||
for _, r := range relays {
|
||||
discoI := &xmpp.DiscoItem{JID: client.JID.Full(), Node: r.Mac, Name: "Relay : "}
|
||||
if (r.Description == "") {
|
||||
discoI.Name += r.Mac
|
||||
} else {
|
||||
discoI.Name += r.Description
|
||||
}
|
||||
discoItem.Item = append(discoItem.Item, *discoI)
|
||||
}
|
||||
|
||||
reply.PayloadEncode(discoItem)
|
||||
client.Out <- reply
|
||||
}
|
||||
|
||||
func execCommandAdHoc(iq *xmpp.Iq) {
|
||||
adHoc := &xmpp.AdHocCommand{}
|
||||
iq.PayloadDecode(adHoc)
|
||||
log.Info("Commande Ad-Hoc reçut. Node : %s", adHoc.Node)
|
||||
|
||||
// For now, we know that the node is the Mac address for a relay
|
||||
relais := relay.GetRelayByMac(adHoc.Node)
|
||||
descriptionRelais := relais.Description
|
||||
if descriptionRelais == "" {
|
||||
descriptionRelais = relais.Mac
|
||||
}
|
||||
if adHoc.SessionId == "" && adHoc.Action == xmpp.ActionAdHocExecute {
|
||||
// First step in the command
|
||||
if relais.Id != 0 {
|
||||
reply := iq.Response(xmpp.IqTypeResult)
|
||||
cmd := &xmpp.AdHocCommand{Node: adHoc.Node, Status: xmpp.StatusAdHocExecute, SessionId: xmpp.SessionId()/*+";"+relais.Mac*/}
|
||||
|
||||
cmdXForm := &xmpp.AdHocXForm{Type: xmpp.TypeAdHocForm, Title: "Commande relais "+descriptionRelais}
|
||||
field := &xmpp.AdHocField{Var: "command", Label: "Commande a executer", Type: "list-single"}
|
||||
fieldOption := &xmpp.AdHocFieldOption{Value: "toggle"}
|
||||
field.Options = append(field.Options, *fieldOption)
|
||||
cmdXForm.Fields = append(cmdXForm.Fields, *field)
|
||||
// TODO, ajouter des commandes pour allumer X seconde (par exemple)
|
||||
|
||||
cmd.XForm = *cmdXForm
|
||||
|
||||
reply.PayloadEncode(cmd)
|
||||
client.Out <- reply
|
||||
}
|
||||
} else if adHoc.Action == xmpp.ActionAdHocExecute {
|
||||
// Last step in the command
|
||||
|
||||
err := relais.Toggle()
|
||||
|
||||
reply := iq.Response(xmpp.IqTypeResult)
|
||||
cmd := &xmpp.AdHocCommand{Node: adHoc.Node, Status: xmpp.StatusAdHocCompleted, SessionId: adHoc.SessionId}
|
||||
|
||||
cmdXForm := &xmpp.AdHocXForm{Type: xmpp.TypeAdHocResult, Title: "Commande relais "+descriptionRelais}
|
||||
cmd.XForm = *cmdXForm
|
||||
|
||||
note := &xmpp.AdHocNote{Type: xmpp.TypeAdHocNoteInfo}
|
||||
if err == nil {
|
||||
note.Value = "Commande effectuée avec succes !"
|
||||
} else {
|
||||
note.Value = "Une erreur c'est produite à l'exécution de la commande…"
|
||||
}
|
||||
cmd.Note = *note
|
||||
|
||||
reply.PayloadEncode(cmd)
|
||||
client.Out <- reply
|
||||
} else if adHoc.Action == xmpp.ActionAdHocCancel {
|
||||
// command canceled
|
||||
reply := iq.Response(xmpp.IqTypeResult)
|
||||
cmd := &xmpp.AdHocCommand{Node: adHoc.Node, Status: xmpp.StatusAdHocCanceled, SessionId: adHoc.SessionId}
|
||||
reply.PayloadEncode(cmd)
|
||||
client.Out <- reply
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue