diff --git a/internal/migrations/files/0004.sql b/internal/migrations/files/0004.sql new file mode 100644 index 0000000..3fd9c96 --- /dev/null +++ b/internal/migrations/files/0004.sql @@ -0,0 +1,10 @@ +CREATE TABLE meter ( + id serial PRIMARY KEY NOT NULL, + name varchar(255) NOT NULL, + fortop_uid varchar(50) NOT NULL +); + +DELETE FROM measurement; + +ALTER TABLE measurement + ADD meter_id integer NOT NULL; diff --git a/internal/model/db.json b/internal/model/db.json index d540094..31c3238 100644 --- a/internal/model/db.json +++ b/internal/model/db.json @@ -4,136 +4,140 @@ "fields": [ { "name": "c_gem_1", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "c_gem_2", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "c_gem_3", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "ep_1", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "ep_2", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "ep_3", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "i_gem_1", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "i_gem_2", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "i_gem_3", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "i_max_1", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "i_max_2", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "i_max_3", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, + { + "name": "meter_id", + "data_type": "integer", + "size": 4 + }, { "name": "p_max_1", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "p_max_2", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "p_max_3", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "s_max_1", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "s_max_2", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "s_max_3", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "time", - "type": "timestamp with time zone", - "null": false, + "data_type": "timestamp with time zone", "size": 8 }, { "name": "u_gem_1", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "u_gem_2", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 }, { "name": "u_gem_3", - "type": "double precision", - "null": false, + "data_type": "double precision", "size": 8 } ] + }, + { + "name": "public.meter", + "alias": "me", + "fields": [ + { + "name": "fortop_uid", + "data_type": "character varying", + "size": 50 + }, + { + "name": "id", + "data_type": "integer", + "size": 4 + }, + { + "name": "name", + "data_type": "character varying", + "size": 255 + } + ] } ] diff --git a/main.go b/main.go index bfdf48f..789e126 100644 --- a/main.go +++ b/main.go @@ -10,7 +10,9 @@ import ( "git.fuyu.moe/5GPowerQuality/parser/internal/model" "git.fuyu.moe/Fuyu/flog" + "git.ultraware.nl/NiseVoid/qb" "git.ultraware.nl/NiseVoid/qb/qbdb" + "git.ultraware.nl/NiseVoid/qb/qc" "git.ultraware.nl/NiseVoid/qb/qf" "golang.org/x/net/html/charset" ) @@ -50,22 +52,31 @@ func fetchData() { end := start.Add(time.Hour) data := GetFortopData(start, end) - ranges := map[string][]Range{} - for _, v := range data { - ranges[v.Naam] = v.Range + ranges := map[int]map[string][]Range{} + for _, meter := range data { + mID := GetMeterID(meter.MeterID) + ranges[mID] = map[string][]Range{} + + for _, v := range meter.Meetwaarde { + ranges[mID][v.Naam] = v.Range + } } - sets := Sets{} - for k, v := range ranges { - for _, r := range v { - date := time.Time(r.Date) - set, ok := sets[date] - if !ok { - sets[date] = Set{} - set = sets[date] - } + sets := map[int]Sets{} + for meter, val := range ranges { + sets[meter] = Sets{} - set[k] = r.Value + for k, v := range val { + for _, r := range v { + date := time.Time(r.Date) + set, ok := sets[meter][date] + if !ok { + sets[meter][date] = Set{} + set = sets[meter][date] + } + + set[k] = r.Value + } } } @@ -81,6 +92,30 @@ func fetchData() { start = GetStartDate() } +// GetMeterID gets the meter ID, if there is none yet a new record is add to meter +func GetMeterID(meterID string) (id int) { + me := model.Meter() + q := me.Select(me.ID). + Where(qc.Eq(me.FortopUID, meterID)) + + err := db.QueryRow(q).Scan(&id) + switch err { + case nil: + case sql.ErrNoRows: + iq := me.Insert(me.Name, me.FortopUID). + Values(``, meterID) + + err = db.QueryRow(qb.Returning(iq, me.ID)).Scan(&id) + if err != nil { + panic(err) + } + default: + panic(err) + } + + return +} + // GetStartDate gets the last measurement date func GetStartDate() time.Time { m := model.Measurement() @@ -100,13 +135,13 @@ func GetStartDate() time.Time { return *t } -func insertSets(sets Sets) { +func insertSets(sets map[int]Sets) { if len(sets) == 0 { return } m := model.Measurement() - q := m.Insert(m.Time, + q := m.Insert(m.Time, m.MeterID, m.CGem1, m.CGem2, m.CGem3, m.Ep1, m.Ep2, m.Ep3, m.IGem1, m.IGem2, m.IGem3, @@ -116,16 +151,18 @@ func insertSets(sets Sets) { m.UGem1, m.UGem2, m.UGem3, ) - for k, v := range sets { - q.Values(k, - v[`CGem1`], v[`CGem2`], v[`CGem3`], - v[`EP1`], v[`EP2`], v[`EP3`], - v[`IGem1`], v[`IGem2`], v[`IGem3`], - v[`IMax1`], v[`IMax2`], v[`IMax3`], - v[`PMax1`], v[`PMax2`], v[`PMax3`], - v[`SMax1`], v[`SMax2`], v[`SMax3`], - v[`UGem1`], v[`UGem2`], v[`UGem3`], - ) + for meter, s := range sets { + for k, v := range s { + q.Values(k, meter, + v[`CGem1`], v[`CGem2`], v[`CGem3`], + v[`EP1`], v[`EP2`], v[`EP3`], + v[`IGem1`], v[`IGem2`], v[`IGem3`], + v[`IMax1`], v[`IMax2`], v[`IMax3`], + v[`PMax1`], v[`PMax2`], v[`PMax3`], + v[`SMax1`], v[`SMax2`], v[`SMax3`], + v[`UGem1`], v[`UGem2`], v[`UGem3`], + ) + } } err := db.Exec(q) @@ -135,7 +172,7 @@ func insertSets(sets Sets) { } // GetFortopData retrieves data from fortop -func GetFortopData(startDate, endDate time.Time) []Meetwaarde { +func GetFortopData(startDate, endDate time.Time) []Meter { url := `https://energy4all.energyportal.online/index?p5g=S_1_` + strconv.FormatInt(startDate.Unix(), 10) + `_` + strconv.FormatInt(endDate.Unix(), 10) resp, err := http.Get(url) if err != nil { @@ -155,5 +192,5 @@ func GetFortopData(startDate, endDate time.Time) []Meetwaarde { panic(err) } - return data.Trafo.Meter.Meetwaarde + return data.Trafo.Meter } diff --git a/type.go b/type.go index 7c7566c..f0d3966 100644 --- a/type.go +++ b/type.go @@ -10,16 +10,19 @@ import ( type FortopFormat struct { XMLName xml.Name `xml:"Trafo-Details"` Trafo struct { - TrafoNummer int `xml:"trafonummer"` - Meter struct { - MeterID int `xml:"meter-id"` - StartDate UnixTimestamp `xml:"startdate"` - EndDate int `xml:"enddate"` - Meetwaarde []Meetwaarde `xml:"meetwaarde"` - } `xml:"meter"` + TrafoNummer int `xml:"trafonummer"` + Meter []Meter `xml:"meter"` } `xml:"trafo"` } +// Meter contains all data from one specific meter +type Meter struct { + MeterID string `xml:"meter-id"` + StartDate UnixTimestamp `xml:"startdate"` + EndDate UnixTimestamp `xml:"enddate"` + Meetwaarde []Meetwaarde `xml:"meetwaarde"` +} + // Meetwaarde contains the data that is not pointless garbage type Meetwaarde struct { Naam string `xml:"naam"`