aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas "Cakeisalie5" Touhey <thomas@touhey.fr>2018-05-22 16:52:55 +0200
committerThomas "Cakeisalie5" Touhey <thomas@touhey.fr>2018-05-22 16:52:55 +0200
commitb7608f63e6006a3404260fc3315a30f30d3af762 (patch)
tree03c5b3a38a3027d45e419e1b6e3eafb90cf29fd8
parente1bdcc57717505f9c9071976a2b7d054b04ba1e0 (diff)
Still working on meter listing.
-rw-r--r--.editorconfig13
-rwxr-xr-xMakefile20
-rwxr-xr-xMakefile.vars16
-rw-r--r--README.rst30
-rw-r--r--daemon/base.c (renamed from daemon/wes.c)133
-rw-r--r--daemon/dummy/if.c195
-rw-r--r--daemon/internals.h659
-rw-r--r--daemon/ip/cfg.c20
-rw-r--r--daemon/ip/if.c880
-rw-r--r--daemon/ip/internals.h8
-rw-r--r--daemon/server.c871
-rw-r--r--include/wesh.hpp273
-rw-r--r--lib/electricity_meter.cpp346
-rw-r--r--lib/helpers.cpp218
-rw-r--r--lib/internals.hpp1
-rw-r--r--lib/meter/clamp.cpp34
-rw-r--r--lib/meter/meter_base.cpp95
-rw-r--r--lib/meter/pulse_meter.cpp34
-rw-r--r--lib/meter/teleinfo_meter.cpp34
-rw-r--r--lib/wes/dummy_wes.cpp (renamed from lib/dummy_wes.cpp)30
-rw-r--r--lib/wes/wes.cpp (renamed from lib/wes.cpp)43
-rw-r--r--lib/wes/wes_base.cpp (renamed from lib/wes_base.cpp)97
-rw-r--r--weshd.x717
23 files changed, 2912 insertions, 1855 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..39165b8
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,13 @@
+# Configuration compatible avec de multiples éditeurs.
+# Voyez http://editorconfig.org pour davantage de détails.
+
+root = true
+
+# Délimiteurs de fin de ligne type Unix, avec délimiteur de fin.
+# Tabulations, faisant quatre colonnes.
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+indent_style = tab
+indent_size = 4
diff --git a/Makefile b/Makefile
index 73ba72b..e0d3594 100755
--- a/Makefile
+++ b/Makefile
@@ -85,7 +85,8 @@ install: install-daemon install-lib install-client
# Dossiers de construction.
# XXX: Temporaire, merci à moi du futur de refaire ça proprement un jour.
- ./build/ ./build/lib/ ./build/rpc/ ./build/daemon/ \
+ ./build/ ./build/rpc/ ./build/daemon/ \
+ ./build/lib/ ./build/lib/wes/ ./build/lib/meter/ \
./build/daemon/ip/ ./build/daemon/dummy/ ./build/client/:
$(call bcmd,mkdir,$@,$(MD) "$@")
@@ -130,7 +131,7 @@ install: install-daemon install-lib install-client
# Création des objets.
$(S_OBJDIR)/%.c.o: $(S_OBJDIR)/%.c $(S_OBJDIR)/$(S_NAME).h | $(S_OBJDIR)/
- $(call bcmd,cc,$@,$(CC) -c -o $@ $<)
+ $(call bcmd,cc,$@,$(CC) -c -o $@ $< $(S_CFLAGS))
# ---
# Définition des targets pour le démon.
@@ -162,18 +163,19 @@ $(eval $(call make-daemon-obj-rule,$(src))))
# ---
# Création de la bibliothèque.
- all-lib: $(CHECKCFG) $(L_DEST) $(L_PKG)
+ all-lib: $(CHECKCFG) $(L_DEST)
$(L_DEST): $(L_DEST).$(MAJOR) | $(dir $(L_DEST))
$(call bcmd,ln,$@,$(LN) $(notdir $(L_DEST).$(MAJOR)) $(L_DEST))
$(L_DEST).$(MAJOR): $(L_OBJ) | $(dir $(L_DEST))
$(call bcmd,ld++,$@,$(LDXX) -o $@ $(L_OBJ) $(L_LDFLAGS))
- $(L_OBJDIR)/%.cpp.o: $(L_SRCDIR)/%.cpp $(L_INC) | $(L_OBJDIR)/
- $(call bcmd,cxx,$@,$(CXX) -c -o $@ $< $(L_CXXFLAGS))
-
- $(L_PKG): | $(dir $(L_PKG))
- $(call bcmd,write-pkg,$@,tools/write-pkg.sh >"$@")
+define make-lib-obj-rule
+ $(L_OBJDIR)/$1.cpp.o: $(L_SRCDIR)/$1.cpp $(L_INC) | $(dir $(L_OBJDIR)/$1)
+ $(call bcmd,cxx,$$@,$(CXX) -c -o $$@ $$< $(L_CXXFLAGS))
+endef
+$(foreach src,$(basename $(L_SRC)),\
+$(eval $(call make-lib-obj-rule,$(src))))
# Installation de la bibliothèque.
@@ -185,7 +187,7 @@ $(eval $(call make-daemon-obj-rule,$(src))))
$(call qcmd,$(LN) $(notdir $(L_DEST).$(MAJOR)) \
$(ILIBDIR)/$(notdir $(L_DEST)))
$(call imsg,Installation du paquet pkg-config.)
- $(call qcmd,install -m 644 $(L_PKG) $(IPKGDIR)/$(notdir $(L_PKG)))
+ $(call qcmd,tools/write-pkg.sh >$(IPKGDIR)/lib$(LIB).pc)
$(call imsg,Installation des headers.)
$(foreach i,$(L_INCp),$(call qcmd,$(INST) -m 644 $(L_INCDIR)/$(i) \
"$(IINCDIR)/lib$(LIB)-$(VERSION)/$(i)"$(\n)))
diff --git a/Makefile.vars b/Makefile.vars
index 5e8448a..e51d75e 100755
--- a/Makefile.vars
+++ b/Makefile.vars
@@ -69,8 +69,8 @@
# SunRPC, pour l'IPC entre la bibliothèque client et le démon.
- DEP_rpc_CFLAGS :=
- DEP_rpc_LIBS := -lnsl
+ DEP_rpc_CFLAGS := $(shell pkg-config libtirpc --cflags)
+ DEP_rpc_LIBS := $(shell pkg-config libtirpc --libs)
# libwesh, soit la bibliothèque client.
@@ -92,6 +92,10 @@
S_NAME := $(patsubst %.x,%,$(notdir $(S_FROM)))
+# Options.
+
+ S_CFLAGS := $(DEP_rpc_CFLAGS)
+
# ---
# Informations concernant le démon.
# ---
@@ -127,7 +131,6 @@
# Dossiers la concernant.
L_DEST := ./build/lib$(LIB).so
- L_PKG := ./build/lib$(LIB).pc
L_SRCDIR := ./lib
L_INCDIR := ./include
@@ -136,17 +139,18 @@
# Recherche de ses sources.
L_SRC := \
- $(patsubst $(L_SRCDIR)/%,%,$(wildcard $(L_SRCDIR)/*.cpp))
+ $(patsubst $(L_SRCDIR)/%,%,$(wildcard $(L_SRCDIR)/*.cpp \
+ $(L_SRCDIR)/**/*.cpp))
L_OBJ := $(L_SRC:%=$(L_OBJDIR)/%.o) \
$(S_OBJDIR)/$(S_NAME)_xdr.c.o $(S_OBJDIR)/$(S_NAME)_clnt.c.o
L_INCp := $(patsubst $(L_INCDIR)/%,%,$(wildcard \
$(L_INCDIR)/*.hpp $(L_INCDIR)/**/*.hpp))
- L_INC := $(L_INCp:%=$(L_INCDIR)) $(S_OBJDIR)/$(S_NAME).h \
+ L_INC := $(L_INCp:%=$(L_INCDIR)/%) $(S_OBJDIR)/$(S_NAME).h \
$(wildcard $(L_SRCDIR)/*.hpp $(L_SRCDIR)/**/*.hpp)
# Dépendances et options.
- L_DEPS :=
+ L_DEPS := rpc
L_CXXFLAGS := $(CXXFLAGS) $(foreach x,$(L_DEPS),$(DEP_$(x)_CFLAGS)) \
-I $(S_OBJDIR) -fPIC -I $(L_INCDIR)
diff --git a/README.rst b/README.rst
index 57e79a7..5790a6a 100644
--- a/README.rst
+++ b/README.rst
@@ -37,7 +37,8 @@ La contruction de ces composants se fait en deux étapes :
Dépendances
-----------
-- un système `POSIX`_-compliant (sockets, Sun RPC) ;
+- un système `POSIX`_-compliant (sockets).
+- la `libtirpc`_ (interface compatible SunRPC).
- la `libcurl`_ >= 7.0.
-------------
@@ -78,6 +79,19 @@ Les options existantes sont les suivantes :
``none``
N'afficher que les messages non désactivables.
+``--no-delete-scripts``
+
+ Par défaut, ``weshd`` supprime les scripts qu'il téléverse et exécute
+ sur les serveurs WES connectés par IP pour récupérer des variables.
+ Pour du débogage, l'on peut préférer laisser les scripts sur l'appareil
+ distant pour examiner s'ils sont bien formattés et quel résultat
+ ils donnent : c'est ce que fait cette option.
+
+``--libcurl-verbose``, ``--libcurl-http-verbose``, ``--libcurl-ftp-verbose``
+
+ Rend la libcurl un peu plus bavarde lorsque weshd s'en sert,
+ éventuellement pour certains protocoles uniquement.
+
------------
Construction
------------
@@ -104,7 +118,18 @@ deux commandes suivantes :
finaux, et la configuration de l'utilisateur (afin de retrouver l'état
d'origine du dossier du projet).
-**TODO: decode CGX using libxml-2.0 package?**
+-------------
+Documentation
+-------------
+
+Je documente au maximum ce que je comprends des serveurs WES dans le dossier
+``doc/``, notamment les interfaces qu'il faut, dans l'idéal, implémenter
+pour pouvoir communiquer avec lui.
+
+Pour ce qui concerne le code en lui-même, bien que je documente pas mal
+comment le code est organisé dans les fichiers d'en-tête, il n'y a pas encore
+de documentation indépendante ni de document écrit qui décrive ça en détail.
+Ça sera dans notre rapport de stage.
.. _serveurs WES: https://www.cartelectronic.fr/content/8-serveur-wes
.. _Cartelectronic: https://www.cartelectronic.fr/
@@ -120,4 +145,5 @@ deux commandes suivantes :
.. _client: https://fr.wikipedia.org/wiki/Client_(informatique)
.. _POSIX: https://fr.wikipedia.org/wiki/POSIX
.. _libcurl: https://curl.haxx.se/libcurl/
+.. _libtirpc: https://sourceforge.net/projects/libtirpc/
.. _iniparser: http://ndevilla.free.fr/iniparser/
diff --git a/daemon/wes.c b/daemon/base.c
index da260f4..eb0275f 100644
--- a/daemon/wes.c
+++ b/daemon/base.c
@@ -1,5 +1,5 @@
/* ****************************************************************************
- * wes.c -- initialisation, gestion, utilisation d'un serveur WES.
+ * base.c -- initialisation, gestion, utilisation des types de base.
* Copyright (C) 2018 Thomas Touhey <thomas@touhey.fr>
*
* This project is governed by the CeCILL license under French law and
@@ -198,3 +198,134 @@ int set_name(wes_t *wes, const char *name)
return (WROK);
}
+
+/* ---
+ * Correction de structures de données.
+ * --- */
+
+/* `correct_cfg()`: correction de la configuration d'un WES. */
+
+int correct_cfg(wes_t *wes, wescfg_t *cfg, wescfgflags_t flags)
+{
+ flags = ~flags;
+
+ if (flags & WESCFG_NAME)
+ cfg->name = "";
+ if (flags & WESCFG_TIME) {
+ cfg->current_time.year = 1970;
+ cfg->current_time.mon = 1;
+ cfg->current_time.dom = 1;
+ cfg->current_time.hour = 0;
+ cfg->current_time.min = 0;
+ cfg->current_time.sec = 0;
+ cfg->current_time.dow = 3; /* jeudi */
+ cfg->current_time.tzhour = 0;
+ cfg->current_time.tzmin = 0;
+ cfg->current_time.sum = 0;
+ }
+
+ switch (wes->iface->type) {
+ case WESTYPE_IP:
+ {
+ const unsigned char fixed_ip[4] = {0, 0, 0, 0};
+ const unsigned char fixed_mask[4] = {255, 255, 255, 255};
+ const unsigned char fixed_mac[6] = {0, 0, 0, 0, 0, 0};
+
+ if (flags & WESCFG_DHCP)
+ cfg->more.ip.dhcp_enabled = 0;
+ if (flags & WESCFG_IP)
+ memcpy(cfg->more.ip.ip, fixed_ip, 4);
+ if (flags & WESCFG_MASK)
+ memcpy(cfg->more.ip.mask, fixed_mask, 4);
+ if (flags & WESCFG_GW)
+ memcpy(cfg->more.ip.gw, fixed_ip, 4);
+ if (flags & WESCFG_DNS1)
+ memcpy(cfg->more.ip.dns1, fixed_ip, 4);
+ if (flags & WESCFG_DNS2)
+ memcpy(cfg->more.ip.dns2, fixed_ip, 4);
+ if (flags & WESCFG_MAC)
+ memcpy(cfg->more.ip.mac, fixed_mac, 6);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return (WROK);
+}
+
+/* `correct_meter()`: correction d'un compteur. */
+
+int correct_meter(wes_t *wes, wesmetercfg_t *meter, wesmetertype_t type,
+ wesmeterflags_t flags)
+{
+ (void)wes;
+ flags = ~flags;
+
+ if (flags & WESMETER_NAME)
+ meter->name = "";
+ if (flags & WESMETER_READ)
+ meter->is_read = 0;
+ if (flags & WESMETER_MODE)
+ meter->mode = WESMETERMODE_CONSO;
+ if (flags & WESMETER_WHAT)
+ meter->what = WESMETERWHAT_UNKNOWN;
+ if (flags & WESMETER_FIXED_COSTS)
+ meter->fixed_cost = 0.0;
+ if (flags & WESMETER_PRORATA)
+ meter->prorata = 0;
+ if (flags & WESMETER_TYPE)
+ meter->type = WESMETERTYPE_NONE;
+
+ switch (type) {
+ case WESMETERTYPE_AMPER:
+ if (flags & WESMETER_COST)
+ meter->more.amper.cost = 0.0;
+ if (flags & WESMETER_VOLTAGE)
+ meter->more.amper.voltage = 0;
+ break;
+ case WESMETERTYPE_PULSE:
+ if (flags & WESMETER_COST)
+ meter->more.pulse.cost = 0.0;
+ if (flags & WESMETER_METHOD)
+ meter->more.pulse.method = WESPLSMETHOD_ELEC;
+ if (flags & WESMETER_GROUP)
+ meter->more.pulse.group_size = 1;
+ break;
+ case WESMETERTYPE_TELEINFO:
+ if (flags & WESMETER_COSTS_BASE)
+ meter->more.teleinfo.cost_base_th = 0;
+ if (flags & WESMETER_COSTS_HCHP) {
+ meter->more.teleinfo.cost_hchp_hc = 0;
+ meter->more.teleinfo.cost_hchp_hp = 0;
+ }
+ if (flags & WESMETER_COSTS_TEMPO) {
+ meter->more.teleinfo.cost_tempo_hcjb = 0;
+ meter->more.teleinfo.cost_tempo_hpjb = 0;
+ meter->more.teleinfo.cost_tempo_hcjw = 0;
+ meter->more.teleinfo.cost_tempo_hpjw = 0;
+ meter->more.teleinfo.cost_tempo_hcjr = 0;
+ meter->more.teleinfo.cost_tempo_hpjr = 0;
+ }
+ if (flags & WESMETER_COSTS_EJP) {
+ meter->more.teleinfo.cost_ejp_hn = 0;
+ meter->more.teleinfo.cost_ejp_pm = 0;
+ }
+
+ if (flags & WESMETER_BDPV_ENABLED)
+ meter->more.teleinfo.bdpv_enabled = 0;
+ if (flags & WESMETER_BDPV_IDS) {
+ meter->more.teleinfo.bdpv_username = "";
+ meter->more.teleinfo.bdpv_password = "";
+ }
+ if (flags & WESMETER_BDPV_TIME) {
+ meter->more.teleinfo.bdpv_hour = 0;
+ meter->more.teleinfo.bdpv_min = 0;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return (WROK);
+}
diff --git a/daemon/dummy/if.c b/daemon/dummy/if.c
index a2a2650..3b2ed71 100644
--- a/daemon/dummy/if.c
+++ b/daemon/dummy/if.c
@@ -48,14 +48,12 @@ static int free_dummy_wes(wes_t *wes)
/* `add_dummy_wes()`: créer une ressource factice. */
-int add_dummy_wes(weslist_t *list, wes_t **wesp, wescreatedata_t *data)
+int add_dummy_wes(weslist_t *list, wes_t **wesp)
{
wes_t *wes;
char dummyname[20];
int err;
- (void)data;
-
/* Allocation de la ressource. */
wes = malloc(sizeof(wes_t));
@@ -81,121 +79,117 @@ int add_dummy_wes(weslist_t *list, wes_t **wesp, wescreatedata_t *data)
}
/* ---
- * Interactions avec l'heure du faux serveur WES (heure locale).
+ * Interactions avec la configuration du faux serveur WES (heure locale).
* --- */
-static int setfakename(wes_t *wes, const char *name)
-{
- /* En fait, on n'a pas d'appareil distant sur lequel définir le nom,
- * donc du coup c'est bon directement. Le serveur va se charger
- * de définir le nom dans la base de la ressource. */
-
- (void)wes;
- (void)name;
-
- return (WROK);
-}
+/* `getfakecfg()`: Récupération de la configuration depuis le serveur
+ * WES factice. */
-static int getfaketime(wes_t *wes, westime_object_t **dtp)
+static int getfakecfg(wes_t *wes, wescfgflags_t flags, wescfg_t **cfgp)
{
- static westime_object_t dt;
- time_t tp;
- struct tm *tm;
+ static wescfg_t cfg;
+ wesdt_t *dt;
+ time_t tp; struct tm *tm;
(void)wes;
+ (void)flags;
- /* Récupération de la représentation déconstruite du temps. */
+ /* Récupération de l'heure. */
time(&tp);
tm = gmtime(&tp);
- /* Sauvegarde de l'heure */
-
- dt.cfg.dt.year = tm->tm_year + 1900;
- dt.cfg.dt.mon = tm->tm_mon + 1;
- dt.cfg.dt.dom = tm->tm_mday;
- dt.cfg.dt.hour = tm->tm_hour;
- dt.cfg.dt.min = tm->tm_min;
- dt.cfg.dt.sec = tm->tm_sec;
- dt.cfg.dt.dow = tm->tm_wday ? tm->tm_wday - 1 : 6;
- dt.cfg.dt.sum = tm->tm_isdst;
- dt.cfg.dt.tzhour = 0;
- dt.cfg.dt.tzmin = 0;
+ /* Remplissage de la configuration.
+ * Le nom est rempli par le serveur. */
+
+ cfg.free = NULL;
+ dt = &cfg.current_time;
+ dt->year = tm->tm_year + 1900;
+ dt->mon = tm->tm_mon + 1;
+ dt->dom = tm->tm_mday;
+ dt->hour = tm->tm_hour;
+ dt->min = tm->tm_min;
+ dt->sec = tm->tm_sec;
+ dt->dow = tm->tm_wday ? tm->tm_wday - 1 : 6;
+ dt->sum = tm->tm_isdst;
+ dt->tzhour = 0;
+ dt->tzmin = 0;
/* On est bons ! */
- *dtp = &dt;
+ *cfgp = &cfg;
+ return (WROK);
+}
+
+/* `setfakecfg()`: application de la configuration sur le serveur
+ * WES factice. */
+
+static int setfakecfg(wes_t *wes, wescfgflags_t flags, wescfg_t const *cfg)
+{
+ /* On accepte direct, histoire que le nom soit accepté et que
+ * le reste de la configuration aussi, bien que rien de plus que
+ * le nom ne sera modifié. */
+
+ (void)wes;
+ (void)flags;
+ (void)cfg;
+
return (WROK);
}
/* ---
- * Interactions avec le faux compteur branché via TÉLÉINFO.
+ * Interactions avec les (faux) compteurs du WES factice.
* --- */
-static int getfaketic(wes_t *wes, int id, westic_object_t **ticp)
+/* Les compteurs simulés pour le WES factices sont les suivants :
+ * [1] Compteur branché via télé-information. */
+
+/* `getfakemeter()`: Récupération des données d'un compteur du serveur
+ * WES factice. */
+
+static int getfakemeter(wes_t *wes, int id, wesmetertype_t expected,
+ wesmeterflags_t flags, wesmetercfg_t **cfgp)
{
- static westic_object_t tic;
+ static wesmetercfg_t cfg;
static char name[20];
(void)wes;
+ (void)flags;
- if (id < 0 || id > 1)
+ if (id != 1 || expected != WESMETERTYPE_TELEINFO)
return (WROP);
- tic.free = NULL;
-
- sprintf(name, "Faux compteur #%d", id + 1);
- tic.cfg.name = name;
- tic.cfg.is_read = 1;
- tic.cfg.mode = id ? WESMODE_PROD : WESMODE_CONSO;
- tic.cfg.abo = 0.0;
- tic.cfg.prorata = 0;
-
- tic.cfg.tarif_base = 0.0;
- tic.cfg.tarif_hchp_hc = 0.0;
- tic.cfg.tarif_hchp_hp = 0.0;
- tic.cfg.tarif_ejp_hn = 0.0;
- tic.cfg.tarif_ejp_pm = 0.0;
- tic.cfg.tarif_tempo_hcjb = 0.0;
- tic.cfg.tarif_tempo_hpjb = 0.0;
- tic.cfg.tarif_tempo_hcjw = 0.0;
- tic.cfg.tarif_tempo_hpjw = 0.0;
- tic.cfg.tarif_tempo_hcjr = 0.0;
- tic.cfg.tarif_tempo_hpjr = 0.0;
-
- tic.cfg.bdpv_enabled = 0;
- tic.cfg.bdpv_hour = 2;
- tic.cfg.bdpv_min = 30;
-
- tic.data.is_plugged_in = 1;
- tic.data.is_standing_by = 0;
- memcpy(tic.data.adco, "\1\0\1\0\1\0\1\0\1\0\1\0", 12);
- tic.data.phases = 1;
- tic.data.tarif = WESTICTARIF_BASE;
- tic.data.period = WESTICPERIOD_HN;
-
- tic.data.isousc = 45;
- tic.data.pa = 9000;
- tic.data.iinst[0] = 2;
- tic.data.iinst[1] = 0;
- tic.data.iinst[2] = 0;
- tic.data.imax[0] = 5;
- tic.data.imax[1] = 0;
- tic.data.imax[2] = 0;
-
- tic.data.index_base = 624;
- tic.data.index_hchp_hc = 0;
- tic.data.index_hchp_hp = 0;
- tic.data.index_ejp_hn = 0;
- tic.data.index_ejp_pm = 0;
- tic.data.index_tempo_hcjb = 0;
- tic.data.index_tempo_hpjb = 0;
- tic.data.index_tempo_hcjw = 0;
- tic.data.index_tempo_hpjw = 0;
- tic.data.index_tempo_hcjr = 0;
- tic.data.index_tempo_hpjr = 0;
-
- *ticp = &tic;
+ cfg.free = NULL;
+
+ strcpy(name, "Faux compteur TIC");
+ cfg.name = name;
+ cfg.type = WESMETERTYPE_TELEINFO;
+ cfg.is_read = 1;
+ cfg.mode = WESMETERMODE_CONSO;
+ cfg.what = WESMETERWHAT_ELEC;
+
+ cfg.fixed_cost = 0.0;
+ cfg.prorata = 0;
+
+ cfg.more.teleinfo.cost_base_th = 0;
+ cfg.more.teleinfo.cost_hchp_hc = 0;
+ cfg.more.teleinfo.cost_hchp_hp = 0;
+ cfg.more.teleinfo.cost_tempo_hcjb = 0;
+ cfg.more.teleinfo.cost_tempo_hpjb = 0;
+ cfg.more.teleinfo.cost_tempo_hcjw = 0;
+ cfg.more.teleinfo.cost_tempo_hpjw = 0;
+ cfg.more.teleinfo.cost_tempo_hcjr = 0;
+ cfg.more.teleinfo.cost_tempo_hpjr = 0;
+ cfg.more.teleinfo.cost_ejp_hn = 0;
+ cfg.more.teleinfo.cost_ejp_pm = 0;
+
+ cfg.more.teleinfo.bdpv_enabled = 0;
+ cfg.more.teleinfo.bdpv_hour = 23;
+ cfg.more.teleinfo.bdpv_min = 45;
+ cfg.more.teleinfo.bdpv_username = "user.bdpv";
+ cfg.more.teleinfo.bdpv_password = "pw.bdpv";
+
+ *cfgp = &cfg;
return (WROK);
}
@@ -204,10 +198,17 @@ static int getfaketic(wes_t *wes, int id, westic_object_t **ticp)
* --- */
static wesif_t dumif = {
- free_dummy_wes,
- setfakename,
- NULL,
- getfaketime, NULL,
- NULL, NULL,
- getfaketic, NULL
+ WESTYPE_DUMMY, free_dummy_wes,
+
+ /* Interaction avec la configuration. */
+
+ getfakecfg, setfakecfg,
+
+ /* Interaction avec les compteurs. */
+
+ getfakemeter, NULL, NULL,
+
+ /* Listage des compteurs. */
+
+ NULL, NULL, NULL, NULL
};
diff --git a/daemon/internals.h b/daemon/internals.h
index 5bbe2ea..0874ec4 100644
--- a/daemon/internals.h
+++ b/daemon/internals.h
@@ -56,6 +56,7 @@
# define WRNOTFOUND 12 /* Un élément n'a pas été trouvé. */
# define WREXISTS 13 /* Un élément existe déjà. */
# define WRNOITER 14 /* Aucun élément restant dans l'itérateur. */
+# define WRITER 14 /* (alias) */
# define WRNOID 15 /* Il ne reste plus d'identifiants disponibles. */
# define WRTIMEOUT 16 /* Un délai a expiré. */
# define WRAUTH 17 /* Une authentification a échoué. */
@@ -116,93 +117,175 @@ typedef int loglevel_t;
typedef int wesfreemem_t (void*);
/* ---
- * Temps et heure.
+ * Utilitaires.
* --- */
-typedef struct westime {
+/* Horodate (date et heure).
+ * Contient également les données concernant le fuseau horaire. */
+
+typedef struct wesdt {
int year; /* e.g. 2018 */
int mon; /* 1 à 12 */
int dom; /* 1 à 31 */
int hour; /* 0 à 23 */
int min; /* 0 à 59 */
int sec; /* 0 à 60 (leap seconds) */
-
int dow; /* 0 à 6 (lundi à dimanche) */
- int sum; /* « summer time » (heure d'été), 0 si heure d'hiver */
+
int tzhour, tzmin; /* GMT+HH:MM, e.g. 1 puis 45 pour GMT+01:45 */
-} westime_t;
+ int sum; /* « summer time » (heure d'été), 0 si heure d'hiver */
+} wesdt_t;
-typedef struct westimecfg {
- westime_t dt;
+/* Adresse réseau.
+ * Pour le moment, seules les adresses IPv4 et IPv6 sont gérées.
+ * Un appareil peut avoir à la fois une adresse IPv4 et une adresse IPv6. */
- /* TODO: NTP */
-} westimecfg_t;
+# define WNONET 0 /* entrée invalide */
+# define WINET 1 /* ipv4 and ipv6 */
-typedef struct westime_object {
- wesfreemem_t *free;
+# define HASIPv4 1 /* option pour `data.inet.has`: a une adresse ipv4 */
+# define HASIPv6 2 /* option pour `data.inet.has`: a une adresse ipv6 */
- westimecfg_t cfg;
-} westime_object_t;
+typedef struct {
+ int type;
+ union {
+ struct {
+ int has;
+ unsigned char ipv4[4];
+ unsigned char ipv6[16];
+ } inet;
+ } data;
+} wesaddr_t;
/* ---
- * Propriétés réseau.
+ * Définition des options concernant les serveurs WES.
* --- */
-/* Configuration réseau (éléments modifiables). */
+/* Types de serveurs WES existants. */
-typedef struct wesnetcfg {
- /* `dhcp_enabled`: mode DHCP activé ou non.
- * `ip`: adresse ip en l'absence de DHCP.
- * `mask`: masque de sous-réseau en l'absence de DHCP.
- * `gw`: passerelle par défaut en l'absence de DHCP.
- * `ns`: serveurs DNS primaires et secondaires en l'absence de DHCP. */
+typedef enum westype {
+ WESTYPE_NONE,
+ WESTYPE_DUMMY,
+ WESTYPE_IP
+} westype_t;
- int dhcp_enabled;
- unsigned char ip[4];
- unsigned char mask[4];
- unsigned char gw[4];
- unsigned char ns[2][4];
-} wesnetcfg_t;
+/* Configuration du serveur WES, avec type des paramètres. */
-/* Données réseau (éléments non modifiables). */
+# define WESCFG_NAME 1 /* définir le nom */
+# define WESCFG_TIME 2 /* définir l'horodate actuelle. */
-typedef struct wesnetdata {
- /* `mac`: adresse MAC. */
+# define WESCFG_DHCP 4 /* définir le mode DHCP ou non. */
+# define WESCFG_IP 8 /* définir l'IP fixe actuelle */
+# define WESCFG_MASK 16 /* définir le masque de sous-réseau actuel */
+# define WESCFG_GW 32 /* définir la passerelle par défaut actuelle */
+# define WESCFG_DNS1 64 /* définir le serveur de noms primaire */
+# define WESCFG_DNS2 128 /* définir le serveur de noms secondaire */
+# define WESCFG_MAC 256 /* définir l'adresse MAC */
- unsigned char mac[6];
-} wesnetdata_t;
+typedef unsigned long wescfgflags_t;
-/* Toutes les informations concernant l'aspect réseau du serveur WES. */
+typedef struct wescfg {
+ wesfreemem_t *free;
+
+ /* Nom de la ressource (géré par le serveur pour le stockage).
+ * N'est pas nécessairement unique. */
+
+ char *name;
-typedef struct wesnet {
- int (*free)(void);
+ /* Horodate actuelle. */
- wesnetcfg_t cfg;
- wesnetdata_t data;
-} wesnet_object_t;
+ wesdt_t current_time;
-/* Services (pour les identifiants). */
+ /* Plus d'informations selon le type de la ressource. */
-typedef enum wessrvtype {
- WESSRVTYPE_HTTP = 0,
- WESSRVTYPE_FTP = 1,
+ union {
+ /* Pour les ressources de type IP. */
- WESSRVTYPE_BDPV = 32
-} wessrvtype_t;
+ struct {
+ /* Paramètres réseau.
+ * Ne gère que l'IPv4 pour le moment, puisque c'est tout ce que
+ * j'ai besoin de gérer. */
+
+ int dhcp_enabled;
+ unsigned char ip[4];
+ unsigned char mask[4];
+ unsigned char gw[4];
+ unsigned char dns1[4];
+ unsigned char dns2[4];
+
+ unsigned char mac[6]; /* read-only! */
+
+ /* TODO: NTP ? */
+ } ip;
+ } more;
+} wescfg_t;
/* ---
- * Compteur électrique défini via TÉLÉINFO.
+ * Configuration des compteurs (télé-info, impulsions,
+ * pinces ampèremétriques, …).
* --- */
-/* Mode du compteur électrique.
- * Le mode de production est pour, par exemple, les panneaux solaires. */
+/* Type de compteur.
+ * `NONE`: aucun, informations génériques uniquement.
+ * `TELEINFO`: compteur branché via le protocole télé-informatique d'Enedis.
+ * `AMPER`: pinces ampèremétriques.
+ * `PULSE`: compteur d'impulsions. */
-typedef enum westicmode {
- WESMODE_CONSO,
- WESMODE_PROD
-} wesmode_t;
+typedef enum wesmetertype {
+ WESMETERTYPE_NONE,
+ WESMETERTYPE_AMPER,
+ WESMETERTYPE_PULSE,
+ WESMETERTYPE_TELEINFO
+} wesmetertype_t;
-/* Type de tarif auquel un compteur électrique peut se soumettre. */
+/* Mode du compteur électrique.
+ * `CONSO`: consommation.
+ * `PROD`: production (panneaux solaires, …). */
+
+typedef enum wesmetermode {
+ WESMETERMODE_CONSO,
+ WESMETERMODE_PROD
+} wesmetermode_t;
+
+/* Grandeur mesurée par le compteur.
+ * `UNKNOWN`: inconnu.
+ * `WATER`: eau froide/chaude.
+ * `GAS`: gaz.
+ * `ELEC`: électricité.
+ * `FUEL`: fioul. */
+
+typedef enum wesmeterwhat {
+ WESMETERWHAT_UNKNOWN,
+ WESMETERWHAT_WATER,
+ WESMETERWHAT_GAS,
+ WESMETERWHAT_ELEC,
+ WESMETERWHAT_FUEL
+} wesmeterwhat_t;
+
+/* Unité utilisée pour les valeurs du compteur.
+ * `UNKNOWN`: inconnu.
+ * `WH`: watts par heure (Wh).
+ * `KWH`: kilo-watts par heure (kWh).
+ * `LITER`: litres (L).
+ * `CUBICMETER`: mètres cube (m³). */
+
+typedef enum wesmeterunit {
+ WESMETERUNIT_UNKNOWN,
+ WESMETERUNIT_WH,
+ WESMETERUNIT_KWH,
+ WESMETERUNIT_LITER,
+ WESMETERUNIT_CUBICMETER
+} wesmeterunit_t;
+
+/* Type de tarif pour le protocole télé-informatique d'ERDF.
+ * `BASE`: forfait Base (toutes heures), le prix du kWh ne varie pas en
+ * fonction de la période de consommation ;
+ * `HCHP`: forfait Heures Pleines Heures Creuses, le prix du kWh varie
+ * en fonction de l'heure de la journée ;
+ * `TEMPO`: forfait Temporaire, le prix du kWh varie en fonction de l'heure
+ * de la journée, ainsi que de la couleur de la journée ;
+ * `EJP`: forfait Effacement de Jour de Pointe, le prix du kWh varie en
+ * fonction de la journée. */
typedef enum westictarif {
WESTICTARIF_BASE,
@@ -211,236 +294,233 @@ typedef enum westictarif {
WESTICTARIF_TEMPO
} westictarif_t;
-/* Période tarifaire.
- * La signification de celle-ci est liée au type de tarif auquel l'abonné
- * a souscrit. */
+/* Période tarifaire pour le protocole télé-informatique d'ERDF.
+ * La signification des valeurs dans cette énumération dépend du forfait
+ * souscrit pour ce compteur.
+ * Cette structure est pensée comme un champ de bits puisque les
+ * valeurs peuvent couvrir plusieurs périodes.
+ *
+ * Forfait BASE :
+ * `TH`: toutes heures.
+ *
+ * Forfait HCHP :
+ * `HC`: heures creuses.
+ * `HP`: heures pleines.
+ *
+ * Forfait TEMPO :
+ * `HC`: heures creuses.
+ * `HP`: heures pleines.
+ * `JB`: jours bleus.
+ * `JW`: jours blancs.
+ * `JR`: jours rouges.
+ *
+ * Forfait EJP :
+ * `HN`: heures normales.
+ * `PM`: pointes mobiles. */
typedef enum westicperiod {
- WESTICPERIOD_HN = 0, /* Heures Normales/Toutes les Heures */
- WESTICPERIOD_HC = 1, /* Heures Creuses (HCHP, TEMPO) */
- WESTICPERIOD_HP = 2, /* Heures Pleines (HCHP, TEMPO) */
- WESTICPERIOD_PM = 3, /* Heures de Pointe Mobile (EJP) */
-
- WESTICPERIOD_JB = 0, /* Jours Bleus */
- WESTICPERIOD_JW = 4, /* Jours Blancs */
- WESTICPERIOD_JR = 8 /* Jours Rouges */
+ WESTICPERIOD_TH = 1,
+
+ WESTICPERIOD_HC = 1,
+ WESTICPERIOD_HP = 2,
+
+ WESTICPERIOD_JB = 4,
+ WESTICPERIOD_JW = 8,
+ WESTICPERIOD_JR = 16,
+
+ WESTICPERIOD_HN = 1,
+ WESTICPERIOD_PM = 2
} westicperiod_t;
-/* Configuration d'un compteur électrique branché par télé-informatique. */
+/* Méthode de mesure pour les compteurs à impulsions.
+ * `ILS`: impulsions mécaniques.
+ * `ELEC`: impulsions électroniques. */
-typedef struct westiccfg {
- /* Propriétés de base.
- * `name`: nom du compteur.
- * `is_read`: le compteur est-il lu ?
- * `mode`: le compteur est-il en mode consommation ou production ? */
+typedef enum wesplsmethod {
+ WESPLSMETHOD_ILS,
+ WESPLSMETHOD_ELEC
+} wesplsmethod_t;
- char *name;
- int is_read;
- wesmode_t mode;
+/* Drapeaux d'éléments de la structure à récupérer/définir. */
- /* Propriétés tarifaire.
- * `abo`: coûts fixes de l'abonnement actuel.
- * `prorata`: prorata abonnement au prix du kWh ou non.
- * `tarif_*`: tarif pour un abonnement et une période tarifaire donnée. */
+# define WESMETER_NAME 1
+# define WESMETER_READ 2
+# define WESMETER_MODE 4
+# define WESMETER_WHAT 8
+# define WESMETER_TYPE 16
+# define WESMETER_FIXED_COSTS 32
+# define WESMETER_PRORATA 64
- double abo;
- int prorata;
+# define WESMETER_COST 128
+# define WESMETER_VOLTAGE 256
- double tarif_base;
- double tarif_hchp_hc;
- double tarif_hchp_hp;
- double tarif_ejp_hn;
- double tarif_ejp_pm;
- double tarif_tempo_hcjb;
- double tarif_tempo_hpjb;
- double tarif_tempo_hcjw;
- double tarif_tempo_hpjw;
- double tarif_tempo_hcjr;
- double tarif_tempo_hpjr;
-
- /* Configuration BDPV. */
-
- int bdpv_enabled;
- int bdpv_hour;
- int bdpv_min;
-} westiccfg_t;
-
-/* Données détectées concernant le compteur électrique branché par
- * télé-informatique. */
-
-typedef struct westicdata {
- /* Propriétés de base.
- * `is_plugged_in`: un compteur est détecté et en train d'émettre.
- * `is_standing_by`: le compteur n'est pas en mode émission. */
-
- int is_plugged_in;
- int is_standing_by;
-
- /* `adco`: identification du compteur (sur douze chiffres décimaux).
- * `tarif`: type de tarif.
- * `period`: période tarifaire actuelle.
- * `phases`: nombre de phases. */
-
- unsigned char adco[12];
- int phases;
- westictarif_t tarif;
- westicperiod_t period;
-
- /* `isousc`: intensité souscrite.
- * `pa`: puissance apparente (en VA).
- * `iinst`: intensité instantanée pour chaque phase (en A).
- * `imax`: intensité maximale pour chaque phase (en A). */
-
- unsigned int isousc;
- unsigned int pa;
- unsigned int iinst[3];
- unsigned int imax[3];
-
- /* Index pour les différents abonnements. */
-
- unsigned long index_base;
- unsigned long index_hchp_hc;
- unsigned long index_hchp_hp;
- unsigned long index_ejp_hn;
- unsigned long index_ejp_pm;
- unsigned long index_tempo_hcjb;
- unsigned long index_tempo_hpjb;
- unsigned long index_tempo_hcjw;
- unsigned long index_tempo_hpjw;
- unsigned long index_tempo_hcjr;
- unsigned long index_tempo_hpjr;
-} westicdata_t;
-
-/* Toutes les informations concernant un compteur branché via TÉLÉINFO. */
-
-typedef struct westic {
- wesfreemem_t *free;
+# define WESMETER_METHOD 256
+# define WESMETER_GROUP 512
- westiccfg_t cfg;
- westicdata_t data;
-} westic_object_t;
+# define WESMETER_COSTS_BASE 128
+# define WESMETER_COSTS_HCHP 256
+# define WESMETER_COSTS_TEMPO 512
+# define WESMETER_COSTS_EJP 1024
+# define WESMETER_BDPV_ENABLED 2048
+# define WESMETER_BDPV_IDS 4096
+# define WESMETER_BDPV_TIME 8192
-typedef struct westicdata_object {
- wesfreemem_t *free;
+typedef unsigned long wesmeterflags_t;
- westicdata_t data;
-} westicdata_object_t;
+/* Configuration d'un compteur électrique branché par télé-informatique. */
-/* ---
- * Pinces ampèremétriques.
- * --- */
+# define cost_bbr_hcjb cost_tempo_hcjb
+# define cost_bbr_hpjb cost_tempo_hpjb
+# define cost_bbr_hcjw cost_tempo_hcjw
+# define cost_bbr_hpjw cost_tempo_hpjw
+# define cost_bbr_hcjr cost_tempo_hcjr
+# define cost_bbr_hpjr cost_tempo_hpjr
-typedef struct wespcecfg {
- /* Propriétés de base :
- * `name`: nom de la pince.
- * `is_read`: la pince est-elle lue ?
- * `mode`: mode consommation ou production du compteur. */
+typedef struct wesmetercfg {
+ wesfreemem_t *free;
+
+ /* Propriétés de base.
+ * `name`: nom du compteur.
+ * `type`: type du compteur.
+ * `is_read`: le compteur est-il lu ou ignoré par le système ?
+ * `mode`: mode de consommation/production du compteur.
+ * `what`: grandeur mesurée. */
char *name;
+ wesmetertype_t type;
int is_read;
- wesmode_t mode;
-
- /* Propriétés.
- * `voltage`: tension en V ;
- * `tic_id`: reprendre coûts d'un compteur ;
- * `cost`: coût par kWh si `tic_id < 0`. */
+ wesmetermode_t mode;
+ wesmeterwhat_t what;
- int voltage;
- int tic_id;
- double cost;
-} wespcecfg_t;
+ /* Informations concernant le coût.
+ * `fixed_cost`: coût fixe de l'abonnement, à l'année.
+ * `prorata`: l'abonement est-il au prorata du prix de l'unité ? */
-typedef struct wespcedata {
- /* Index: énergie consommée en Wh (XXX: depuis quand ? */
+ double fixed_cost;
+ int prorata;
- unsigned long index;
-} wespcedata_t;
+ /* Informations dépendant du type de compteur. */
+ union {
+ struct {
+ /* Propriétés relatives aux compteurs de types pinces
+ * ampèremétriques.
+ * `voltage`: tension (en V).
+ * `cost`: coût de l'unité (en €). */
-typedef struct wespce_object {
- wesfreemem_t *free;
+ int voltage;
+ double cost;
+ } amper;
- wespcecfg_t cfg;
- wespcedata_t data;
-} wespce_object_t;
+ struct {
+ /* Propriétés relatives aux compteurs d'impulsions.
+ * `method`: méthode de comptage d'impulsions.
+ * `group_size`: nombre d'impulsions par unité.
+ * `cost`: coût de l'unité. */
-typedef struct wespcedata_object {
- wesfreemem_t *free;
+ wesplsmethod_t method;
+ int group_size;
+ double cost;
+ } pulse;
- wespcedata_t data;
-} wespcedata_object_t;
+ struct {
+ /* Propriétés relatives aux compteurs branchés via le protocole
+ * de télé-information défini par Enedis.
+ * `cost_<abo>_<période>`: coût du kWh pendant une période
+ * lorsqu'un forfait est en vigueur.
+ * `bdpv_enabled`: envoyer (ou non) les données via BDPV.
+ * `bdpv_hour`, `bdpv_min`: heure d'envoi via BDPV. */
+
+ double cost_base_th;
+ double cost_hchp_hc;
+ double cost_hchp_hp;
+ double cost_tempo_hcjb;
+ double cost_tempo_hpjb;
+ double cost_tempo_hcjw;
+ double cost_tempo_hpjw;
+ double cost_tempo_hcjr;
+ double cost_tempo_hpjr;
+ double cost_ejp_hn;
+ double cost_ejp_pm;
+
+ int bdpv_enabled;
+ int bdpv_hour, bdpv_min;
+ char *bdpv_username;
+ char *bdpv_password;
+ } teleinfo;
+ } more;
+} wesmetercfg_t;
/* ---
- * Compteurs d'impulsions.
+ * Valeurs retournées pour une période.
* --- */
-typedef enum wesplstype {
- WESPLSTYPE_WATER = 0, /* eau froide/chaude */
- WESPLSTYPE_GAS = 1, /* gaz */
- WESPLSTYPE_ELEC = 2, /* electricité */
- WESPLSTYPE_FUEL = 3 /* fioul */
-} wesplstype_t;
-
-typedef enum wesplsmethod {
- WESPLSMETHOD_ILS = 0, /* mécanique */
- WESPLSMETHOD_ELEC = 1, /* électronique */
-} wesplsmethod_t;
-
-typedef enum wesplsunit {
- WESPLSUNIT_LITER = 0, /* litres */
- WESPLSUNIT_CUBEMETER = 1, /* m³ */
- WESPLSUNIT_WH = 2, /* Wh */
- WESPLSUNIT_KWH = 3 /* kWh */
-} wesplsunit_t;
+typedef struct wesmetervalues {
+ wesfreemem_t *free;
-typedef struct wesplscfg {
- /* Propriétés de base :
- * `name`: nom du compteur d'impulsions.
- * `is_read` le compteur est-elle lu ?
- * `mode`: mode production ou consommation du compteur. */
+ /* Valeurs de base.
+ * `type`: type du compteur (rappel).
+ * `
+ * `active`: le compteur a-t-il été actif (branché, envoyant des valeurs)
+ * pour cette période ?
+ * `count`: nombre d'unités détectées pendant cette période.
+ * `unit`: unité de mesure pour la valeur précédente. */
- char *name;
- int is_read;
- wesmode_t mode;
-
- /* Propriétés.
- * `type`: type d'impulsion (qu'est-ce qui est mesuré) ;
- * `method`: méthode de mesure des impulsions ;
- * `unit`: unité de mesure par unité de groupe d'impulsions ;
- * `group`: nombre d'impulsions par groupe ;
- * `tic_id`: reprendre coûts d'un compteur ;
- * `cost_year`: coût par an en € si `tic_id < 0` ;
- * `cost`: coût par unité si `tic_id < 0`. */
-
- wesplstype_t type;
- wesplsmethod_t method;
- wesplsunit_t unit;
- int group;
- int tic_id;
- double cost_year;
- double cost;
-} wesplscfg_t;
-
-typedef struct wesplsdata {
- /* Données variant.
- * `index`: index actuel.
- * `today`: impulsions aujourd'hui. */
-
- unsigned long index;
- int today;
-} wesplsdata_t;
-
-typedef struct wespls_object {
- wesfreemem_t *free;
+ wesmetertype_t type;
- wesplscfg_t cfg;
- wesplsdata_t data;
-} wespls_object_t;
+ int active;
+ double count;
+ wesmeterunit_t unit;
-typedef struct wesplsdata_object {
- wesfreemem_t *free;
+ /* Valeurs supplémentaires selon le type du compteur. */
- wesplsdata_t data;
-} wesplsdata_object_t;
+ union {
+ struct {
+ /* Valeurs supplémentaires du compteur branché via
+ * télé-informatique.
+ *
+ * `adco`: numéro ADCO du compteur (un chiffre direct par case).
+ * `phases`: nombre de phases (monophasé: 1, triphasé: 3).
+ * `period`: périodes tarifaires sur la période.
+ * `isousc`: intensité souscrite.
+ * `pa`: puissance apparente (en VA).
+ * `iinst`: intensité instantanée pour chaque phase.
+ * `imax`: intensité maximale pour chaque phase. */
+
+ unsigned char adco[12];
+ int phases;
+ westicperiod_t period;
+
+ unsigned int isousc;
+ unsigned int pa;
+ unsigned int iinst[3];
+ unsigned int imax[3];
+
+ /* Index pour chacun des tarifs, avec le tarif en vigueur. */
+
+ union {
+ struct {
+ unsigned long th;
+ } base;
+ struct {
+ unsigned long hc;
+ unsigned long hp;
+ } hchp;
+ struct {
+ unsigned long hcjb;
+ unsigned long hpjb;
+ unsigned long hcjw;
+ unsigned long hpjw;
+ unsigned long hcjr;
+ unsigned long hpjr;
+ } tempo;
+ struct {
+ unsigned long hn;
+ unsigned long pm;
+ } ejp;
+ } indexes;
+ } teleinfo;
+ } more;
+} wesmetervalues_t;
/* ---
* Définition des interfaces.
@@ -461,49 +541,49 @@ typedef struct wes wes_t;
* à utiliser. Ces fonctions correspondent plus ou moins aux besoins du
* serveur. */
+typedef int wesif_free_t (wes_t *);
+
+typedef int wesif_getcfg_t (wes_t *, wescfgflags_t, wescfg_t **);
+typedef int wesif_setcfg_t (wes_t *, wescfgflags_t, wescfg_t const *);
+
+typedef int wesif_getmeter_t (wes_t *, int, wesmetertype_t, wesmeterflags_t,
+ wesmetercfg_t **);
+typedef int wesif_setmeter_t (wes_t *, int, wesmeterflags_t,
+ wesmetercfg_t const *);
+typedef int wesif_getmetervalues_t (wes_t *, wesmetervalues_t **);
+
+typedef int wesif_getmeteriter_t (wes_t *, wesmetertype_t type, void **);
+typedef int wesif_getmeternext_t (void *, int *, wesmetertype_t *type);
+typedef int wesif_skipmeters_t (void *, int);
+typedef void wesif_delmeteriter_t (void *);
+
typedef struct wesif {
- int (*free)(wes_t *wes);
+ westype_t type;
+ wesif_free_t *free;
+
+ /* Interact with the WES configuration. */
- int (*setname)(wes_t *wes, const char *name);
- int (*setsrvids)(wes_t *wes, wessrvtype_t service,
- const char *name, const char *pass);
+ wesif_getcfg_t *getcfg;
+ wesif_setcfg_t *setcfg;
- int (*gettime)(wes_t *wes, westime_object_t **dt);
- int (*settime)(wes_t *wes, westimecfg_t const *cfg);
+ /* Interact with the meters. */
- int (*getnet)(wes_t *wes, wesnet_object_t **net);
- int (*setnet)(wes_t *wes, wesnetcfg_t const *cfg);
+ wesif_getmeter_t *getmeter;
+ wesif_setmeter_t *setmeter;
+ wesif_getmetervalues_t *getmetervalues;
- int (*gettic)(wes_t *wes, int id, westic_object_t **tic);
- int (*getticdata)(wes_t *wes, int id, westime_t const *dt,
- westicdata_object_t **ticdata);
- int (*settic)(wes_t *wes, int id, westiccfg_t const *cfg);
+ /* List meters. */
+
+ wesif_getmeteriter_t *getmeteriter;
+ wesif_getmeternext_t *getmeternext;
+ wesif_skipmeters_t *skipmeters;
+ wesif_delmeteriter_t *delmeteriter;
} wesif_t;
/* ---
* Données de création.
* --- */
-/* Parmi ces données, dont le rôle est décrit ci-dessous, on trouve
- * l'adresse IP, dont la définition par le serveur est la suivante : */
-
-# define WNONET 0 /* entrée invalide */
-# define WINET 1 /* ipv4 and ipv6 */
-
-# define HASIPv4 1 /* option pour `data.inet.has`: a une adresse ipv4 */
-# define HASIPv6 2 /* option pour `data.inet.has`: a une adresse ipv6 */
-
-typedef struct {
- int type;
- union {
- struct {
- int has;
- unsigned char ipv4[4];
- unsigned char ipv6[16];
- } inet;
- } data;
-} wesaddr_t;
-
/* Aux constructeurs de ressources de type WES, on passe toujours un set
* de paramètres déterminé systématiquement à partir de ce que donne le client
* (ne serait-ce que rempli avec les valeurs par défaut par le serveur).
@@ -630,8 +710,8 @@ extern void log_mem(loglevel_t loglevel, const char *func,
/* Macros principales, qui redirigent vers les fonctions de log.
* Utilisez les doubles parenthèses de la façon suivante :
*
- * msg((WLDEBUG, "ma %schaîne de formattage %d", "merveilleuse ", 1));
- * mem((WLWARN, ma_zone_de_memoire, la_taille_de_ma_zone_de_memoire));
+ * msg((wldebug, "ma %schaîne de formattage %d", "merveilleuse ", 1));
+ * mem((wlwarn, ma_zone_de_memoire, la_taille_de_ma_zone_de_memoire));
*
* Il s'agit de macros variadiques, mais compatibles K&R/ANSI C. */
@@ -649,9 +729,10 @@ extern loglevel_t decode_log_level(const char *text);
/* Création et ajout à la liste de serveurs WES de différents types. */
-extern int add_ip_wes(weslist_t *list, wes_t **wesp, wescreatedata_t *data);
-extern int add_dummy_wes(weslist_t *list, wes_t **wesp,
- wescreatedata_t *data);
+extern int add_ip_wes(weslist_t *list, wes_t **wesp, wesaddr_t const *addr,
+ char *http_username, char *http_password,
+ char *ftp_username, char *ftp_password);
+extern int add_dummy_wes(weslist_t *list, wes_t **wesp);
/* Initialiser la base d'un serveur WES. */
@@ -680,6 +761,12 @@ extern void free_name(char *name);
extern int assign_name(wes_t *wes, char *name);
extern int set_name(wes_t *wes, const char *name);
+/* Initialisation des structures de données. */
+
+extern int correct_cfg(wes_t *wes, wescfg_t *cfg, wescfgflags_t flags);
+extern int correct_meter(wes_t *wes, wesmetercfg_t *meter,
+ wesmetertype_t type, wesmeterflags_t flags);
+
/* ---
* Gestion de la liste.
* --- */
diff --git a/daemon/ip/cfg.c b/daemon/ip/cfg.c
index 26a7dd5..231630a 100644
--- a/daemon/ip/cfg.c
+++ b/daemon/ip/cfg.c
@@ -128,7 +128,7 @@ static int normalize_value(char *buf, const char *src)
static int emptysection(wescfgsec_t *sec)
{
- wescfg_t *cfg;
+ wescfgkey_t *cfg;
while ((cfg = sec->child)) {
sec->child = cfg->next;
@@ -143,7 +143,7 @@ static int emptysection(wescfgsec_t *sec)
static int setsectionkeyval(wescfgsec_t *sec, const char *key, const char *val)
{
- wescfg_t **cfgp, *cfg;
+ wescfgkey_t **cfgp, *cfg;
const char *temp;
size_t keysz, valsz;
@@ -164,7 +164,7 @@ static int setsectionkeyval(wescfgsec_t *sec, const char *key, const char *val)
}
}
- cfg = malloc(sizeof(wescfg_t) + keysz + valsz);
+ cfg = malloc(sizeof(wescfgkey_t) + keysz + valsz);
if (!cfg)
return (WRALLOC);
cfg->next = *cfgp;
@@ -353,7 +353,7 @@ static int gathersection(wes_t *wes, wescfgsec_t *sec)
#define SC_NEXT 4
struct sendcookie {
- wescfg_t *cfg;
+ wescfgkey_t *cfg;
int step, err;
size_t off;
};
@@ -363,7 +363,7 @@ struct sendcookie {
static size_t sendsection_callback(char *buffer, size_t blocksize, size_t size,
struct sendcookie *cookie)
{
- wescfg_t *cfg;
+ wescfgkey_t *cfg;
const char *tocopy;
size_t off, csize, copysize;
size_t wr = 0;
@@ -433,7 +433,7 @@ static int sendsection(wes_t *wes, wescfgsec_t *sec)
CURL *curl; CURLcode cres;
struct sendcookie cookie;
curl_off_t fsize;
- wescfg_t *cfg;
+ wescfgkey_t *cfg;
int err;
/* On calcule le nombre total de bytes que cela va prendre. */
@@ -536,10 +536,10 @@ static int getsection(wes_t *wes, wescfgsec_t **secresp, const char *section)
}
static int getsectionkey(wes_t *wes, const char *section, const char *key,
- wescfg_t **cfgp)
+ wescfgkey_t **cfgp)
{
wescfgsec_t *sec;
- wescfg_t *cfg;
+ wescfgkey_t *cfg;
size_t keysz;
int err;
@@ -590,7 +590,7 @@ static int setsectionkey(wes_t *wes, const char *section, const char *key,
static int delsectionkey(wes_t *wes, const char *section, const char *key)
{
wescfgsec_t *sec;
- wescfg_t **cfgp, *cfg, *next;
+ wescfgkey_t **cfgp, *cfg, *next;
size_t keysz; int err;
/* Récupération de la section. */
@@ -628,7 +628,7 @@ static int delsectionkey(wes_t *wes, const char *section, const char *key)
int get_config(wes_t *wes, const char *section_src, const char *key_src,
char *buf, size_t len)
{
- int err; wescfg_t *cfg;
+ int err; wescfgkey_t *cfg;
char section[SECSIZE + 1];
char key[KEYSIZE + 1];
diff --git a/daemon/ip/if.c b/daemon/ip/if.c
index a46900e..0495a4a 100644
--- a/daemon/ip/if.c
+++ b/daemon/ip/if.c
@@ -30,12 +30,14 @@
#include "internals.h"
#define msgcgi(VAR, DESC) \
msg((wlerror, "did CGI " VAR " (" DESC ") definition change?"));
-#define GETCGI(NUM, BLK) { \
- int getcgi_err; \
- if ((getcgi_err = get_cgi(wes, (NUM), (BLK)))) { \
- msg((wlerror, "cgi error: %s", error_string(getcgi_err))); \
- return (getcgi_err); \
- }}
+#define GETCGI(NUM, BLK) \
+ { \
+ int getcgi_err; \
+ if ((getcgi_err = get_cgi(wes, (NUM), (BLK)))) { \
+ msg((wlerror, "cgi error: %s", error_string(getcgi_err))); \
+ return (getcgi_err); \
+ } \
+ }
static wesif_t ipif;
@@ -72,7 +74,9 @@ static int free_ip_wes(wes_t *wes)
/* `make_ip_wes()`: Création bête et méchante d'une ressource WES de la
* classe courante. Ce n'est pas cette fonction qui sera publique */
-static int make_ip_wes(wes_t **wesp, wescreatedata_t *data)
+static int make_ip_wes(wes_t **wesp, wesaddr_t const *addr,
+ char *http_username, char *http_password,
+ char *ftp_username, char *ftp_password)
{
int err;
wes_t *wes;
@@ -90,7 +94,7 @@ static int make_ip_wes(wes_t **wesp, wescreatedata_t *data)
return (err);
}
- memcpy(&wes->addr, &data->addr, sizeof(wes->addr));
+ memcpy(&wes->addr, &addr, sizeof(wes->addr));
wes->sections = NULL;
wes->data = NULL;
@@ -101,12 +105,21 @@ static int make_ip_wes(wes_t **wesp, wescreatedata_t *data)
wes->ftp_name = NULL;
wes->ftp_pass = NULL;
- /* TODO: use `data` here */
+ /* TODO: Il faudrait peut-être initialiser `data` ici… ? */
init_m2m(wes);
- if ((err = set_http_ident(wes, NULL, NULL))
- || (err = set_ftp_ident(wes, NULL, NULL))) {
+ if (http_username && !*http_username)
+ http_username = NULL;
+ if (http_password && !*http_password)
+ http_password = NULL;
+ if (ftp_username && !*ftp_username)
+ ftp_username = NULL;
+ if (ftp_password && !*ftp_password)
+ ftp_password = NULL;
+
+ if ((err = set_http_ident(wes, http_username, http_password))
+ || (err = set_ftp_ident(wes, ftp_username, ftp_password))) {
free_ip_wes(wes);
return (err);
}
@@ -131,8 +144,6 @@ static int make_ip_wes(wes_t **wesp, wescreatedata_t *data)
}
}
- /* TODO: récupération du hostname */
-
*wesp = wes;
return (WROK);
}
@@ -152,20 +163,20 @@ static int make_ip_wes(wes_t **wesp, wescreatedata_t *data)
* standard sur la manière de créer/d'ajouter un nouveau serveur WES
* pour toute interface. */
-int add_ip_wes(weslist_t *list, wes_t **wesp, wescreatedata_t *data)
+int add_ip_wes(weslist_t *list, wes_t **wesp, wesaddr_t const *addr,
+ char *http_username, char *http_password,
+ char *ftp_username, char *ftp_password)
{
wesiter_t iter;
wes_t *wes;
- wesaddr_t *addr;
int err;
/* On vérifie si les paramètres sont OK. */
- addr = &data->addr;
if (addr->type != WINET || ~addr->data.inet.has & HASIPv4
- || addr->data.inet.has & HASIPv6)
+ || addr->data.inet.has & ~HASIPv4)
return (WROP);
- /* TODO: check if IPv4 adress is valid, not broadcast, etc? */
+ /* TODO: check if IPv4 address is valid, not broadcast, etc? */
/* On vérifie si une entrée correspondante n'existe pas déjà. */
@@ -185,7 +196,7 @@ int add_ip_wes(weslist_t *list, wes_t **wesp, wescreatedata_t *data)
/* L'adresse correspond, mince, ça veut dire qu'on a failli
* créer un duplicata ! Ne le créons pas, et renvoyons plutôt
- * celui-ci avec le fait qu'il existe. */
+ * celui-ci en précisant qu'il existe déjà. */
*wesp = wes;
return (WREXISTS);
@@ -193,7 +204,9 @@ int add_ip_wes(weslist_t *list, wes_t **wesp, wescreatedata_t *data)
/* Aucune entrée n'existe avec cette IP, créons-la ! */
- if ((err = make_ip_wes(&wes, data)))
+ err = make_ip_wes(&wes, addr, http_username, http_password,
+ ftp_username, ftp_password);
+ if (err)
return (err);
/* Et ajoutons l'entrée à la liste. */
@@ -208,233 +221,254 @@ int add_ip_wes(weslist_t *list, wes_t **wesp, wescreatedata_t *data)
}
/* ---
- * Configuration des identifiants.
+ * Gestion de la configuration du serveur WES.
* --- */
-static int setwesids(wes_t *wes, wessrvtype_t service,
- const char *name, const char *pass)
+static int getwescfg(wes_t *wes, wescfgflags_t flags, wescfg_t **cfgp)
{
- if (service != WESSRVTYPE_HTTP && service != WESSRVTYPE_FTP
- && service != WESSRVTYPE_BDPV)
- return (WROP);
+ static wescfg_t cfg;
- /* TODO: définir les identifiants distants */
- (void)wes;
- (void)name;
- (void)pass;
+ (void)flags;
- return (WRIMPL);
-}
+ /* Préparation de l'objet.
+ * L'élément n'est pas à supprimer puisqu'il est défini de façon statique,
+ * d'où `.free = NULL`.
+ * De plus, le nom est géré par le serveur (qui le stocke depuis qu'on
+ * l'a ajouté avec la fonction d'ajout/création). */
-/* ---
- * Configuration de l'horodate.
- * --- */
+ cfg.free = NULL;
+ cfg.name = NULL;
-/* `getwestime()`: récupération de l'horodate actuelle d'un serveur WES */
+ /* Récupération des éléments. */
-static int getwestime(wes_t *wes, westime_object_t **dtp)
-{
- static westime_object_t dt;
- char datebuf[20], timebuf[20], gmtbuf[10], sumbuf[10],
- sembuf1[5], sembuf2[5], sembuf3[5], sembuf4[5],
- sembuf5[5], sembuf6[5];
-
- wescgi_t blocks[] = {
- /* La date du jour, sous format numérique `D M Y`. */
- WESCGI("h d", "%d %d %d", datebuf, 20),
-
- /* L'heure courante, sous format numérique `H M S`. */
- WESCGI("h h", "%d %d %d", timebuf, 20),
-
- /* Le fuseau horaire (en nombre entier d'heures). */
- WESCGI("h G", "%d", gmtbuf, 10),
-
- /* Selon si l'on est en heure d'été (activée) ou en
- * heure d'hiver (désactivée). */
- WESCGI("h e", "%.1s", sumbuf, 10),
-
- /* Le jour de la semaine qu'on est (où `g [1-7]` est "selected" si
- * c'est le jour de la semaine actuel, et rien sinon.
- * TODO: peut-être que `g j` fait ça mieux… ? */
- WESCGI("g 1", "%.1s", sembuf1, 5),
- WESCGI("g 2", "%.1s", sembuf2, 5),
- WESCGI("g 3", "%.1s", sembuf3, 5),
- WESCGI("g 4", "%.1s", sembuf4, 5),
- WESCGI("g 5", "%.1s", sembuf5, 5),
- WESCGI("g 6", "%.1s", sembuf6, 5)
- };
-
- GETCGI(10, blocks)
-
- if (blocks[0].lines != 1
- || sscanf(datebuf, "%d%d%d", &dt.cfg.dt.dom, &dt.cfg.dt.mon,
- &dt.cfg.dt.year) < 3) {
- msgcgi("h d", "date");
- return (WRUNKNOWN);
- }
- if (blocks[1].lines != 1
- || sscanf(timebuf, "%d%d%d", &dt.cfg.dt.hour, &dt.cfg.dt.min,
- &dt.cfg.dt.sec) < 3) {
- msgcgi("h h", "hour");
- return (WRUNKNOWN);
- }
+ {
+ char datebuf[20], timebuf[20], gmtbuf[10], sumbuf[10],
+ sembuf1[5], sembuf2[5], sembuf3[5], sembuf4[5],
+ sembuf5[5], sembuf6[5];
+ char dhcpbuf[5], ipbuf[20], msbuf[20], gwbuf[20], dpbuf[20],
+ dsbuf[20], macbuf[30];
- if (blocks[2].lines != 1
- || sscanf(gmtbuf, "%d", &dt.cfg.dt.tzhour) < 1) {
- msgcgi("h G", "gmt");
- return (WRUNKNOWN);
- }
- dt.cfg.dt.tzmin = 0;
+ wescgi_t blocks[] = {
+ /* La date du jour, sous format numérique `D M Y`. */
+ WESCGI("h d", "%d %d %d", datebuf, 20),
- if (blocks[3].lines != 1) {
- msgcgi("h e", "dst");
- return (WRUNKNOWN);
- }
- dt.cfg.dt.sum = sumbuf[0] ? 1 : 0;
+ /* L'heure courante, sous format numérique `H M S`. */
+ WESCGI("h h", "%d %d %d", timebuf, 20),
- if (blocks[4].lines != 1 || blocks[5].lines != 1
- || blocks[6].lines != 1 || blocks[7].lines != 1
- || blocks[8].lines != 1 || blocks[9].lines != 1) {
- msgcgi("g [1-7]", "day of week");
- return (WRUNKNOWN);
- }
- dt.cfg.dt.dow = sembuf1[0] ? 0 : sembuf2[0] ? 1 : sembuf3[0] ? 2 :
- sembuf4[0] ? 3 : sembuf5[0] ? 4 : sembuf6[0] ? 5 : 6;
+ /* Le fuseau horaire (en nombre entier d'heures). */
+ WESCGI("h G", "%d", gmtbuf, 10),
- dt.free = NULL;
- *dtp = &dt;
- return (WROK);
-}
+ /* Selon si l'on est en heure d'été (activée) ou en
+ * heure d'hiver (désactivée). */
+ WESCGI("h e", "%.1s", sumbuf, 10),
-/* ---
- * Configuration réseau.
- * --- */
+ /* Le jour de la semaine qu'on est (où `g [1-7]` est "selected" si
+ * c'est le jour de la semaine actuel, et rien sinon.
+ * TODO: peut-être que `g j` fait ça mieux… ? */
+ WESCGI("g 1", "%.1s", sembuf1, 5),
+ WESCGI("g 2", "%.1s", sembuf2, 5),
+ WESCGI("g 3", "%.1s", sembuf3, 5),
+ WESCGI("g 4", "%.1s", sembuf4, 5),
+ WESCGI("g 5", "%.1s", sembuf5, 5),
+ WESCGI("g 6", "%.1s", sembuf6, 5),
-/* `getwesnet()`: récupération de serveurs WES. */
+ /* Selon si le DHCP est activé (checked) ou désactivé. */
+ WESCGI("r d", "%.1s", dhcpbuf, 5),
-static int getwesnet(wes_t *wes, wesnet_object_t **netp)
-{
- static wesnet_object_t net;
- static wesnetcfg_t *cfg;
- static wesnetdata_t *data;
- char dhcpbuf[5], ipbuf[20], msbuf[20], gwbuf[20], dpbuf[20], dsbuf[20],
- macbuf[30];
+ /* L'adresse IP actuelle. */
+ WESCGI("r i", "%d %d %d %d", ipbuf, 20),
- net.free = NULL;
- cfg = &net.cfg;
- data = &net.data;
+ /* Le masque de sous-réseau actuel. */
+ WESCGI("r m", "%d %d %d %d", msbuf, 20),
- wescgi_t blocks[] = {
- /* Selon si le DHCP est activé (checked) ou désactivé. */
- WESCGI("r d", "%.1s", dhcpbuf, 5),
+ /* La passerelle par défaut actuelle. */
+ WESCGI("r g", "%d %d %d %d", gwbuf, 20),
- /* L'adresse IP actuelle. */
- WESCGI("r i", "%d %d %d %d", ipbuf, 20),
+ /* Les serveurs DNS primaires (p) et secondaires (s). */
+ WESCGI("r p", "%d %d %d %d", dpbuf, 20),
+ WESCGI("r s", "%d %d %d %d", dsbuf, 20),
- /* Le masque de sous-réseau actuel. */
- WESCGI("r m", "%d %d %d %d", msbuf, 20),
+ /* L'adresse MAC du serveur. */
+ WESCGI("r a", "%d %d %d %d %d %d", macbuf, 30)
+ };
- /* La passerelle par défaut actuelle. */
- WESCGI("r g", "%d %d %d %d", gwbuf, 20),
+ GETCGI(17, blocks)
- /* Les serveurs DNS primaires (p) et secondaires (s). */
- WESCGI("r p", "%d %d %d %d", dpbuf, 20),
- WESCGI("r s", "%d %d %d %d", dsbuf, 20),
+ /* ---
+ * Décodage des éléments.
+ * --- */
- /* L'adresse MAC du serveur. */
- WESCGI("r a", "%d %d %d %d %d %d", macbuf, 30)
- };
+ /* Jour du mois, mois, année. */
- /* Extraction des données via CGI, puis décodage. */
+ if (blocks[0].lines != 1 || sscanf(datebuf, "%d%d%d",
+ &cfg.current_time.dom, &cfg.current_time.mon,
+ &cfg.current_time.year) < 3) {
+ msgcgi("h d", "date");
+ return (WRUNKNOWN);
+ }
- GETCGI(7, blocks)
+ /* Heure, minute de l'heure, seconde de la minute. */
- if (blocks[0].lines != 1) {
- msgcgi("r d", "dhcp enabled");
- return (WRUNKNOWN);
- }
- cfg->dhcp_enabled = dhcpbuf[0] ? 1 : 0;
+ if (blocks[1].lines != 1 || sscanf(timebuf, "%d%d%d",
+ &cfg.current_time.hour, &cfg.current_time.min,
+ &cfg.current_time.sec) < 3) {
+ msgcgi("h h", "hour");
+ return (WRUNKNOWN);
+ }
- if (blocks[1].lines != 1
- || sscanf(ipbuf, "%hhu%hhu%hhu%hhu", &cfg->ip[0], &cfg->ip[1],
- &cfg->ip[2], &cfg->ip[3]) < 4) {
- msgcgi("r i", "current ip");
- return (WRUNKNOWN);
- }
- if (blocks[2].lines != 1
- || sscanf(msbuf, "%hhu%hhu%hhu%hhu", &cfg->mask[0],
- &cfg->mask[1], &cfg->mask[2], &cfg->mask[3]) < 4) {
- msgcgi("r m", "netmask");
- return (WRUNKNOWN);
- }
- if (blocks[3].lines != 1
- || sscanf(gwbuf, "%hhu%hhu%hhu%hhu", &cfg->gw[0], &cfg->gw[1],
- &cfg->gw[2], &cfg->gw[3]) < 4) {
- msgcgi("r g", "gateway");
- return (WRUNKNOWN);
- }
- if (blocks[4].lines != 1
- || sscanf(dpbuf, "%hhu%hhu%hhu%hhu", &cfg->ns[0][0],
- &cfg->ns[0][1], &cfg->ns[0][2], &cfg->ns[0][3]) < 4) {
- msgcgi("r p", "primary dns");
- return (WRUNKNOWN);
- }
- if (blocks[5].lines != 1
- || sscanf(dsbuf, "%hhu%hhu%hhu%hhu", &cfg->ns[1][0],
- &cfg->ns[1][1], &cfg->ns[1][2], &cfg->ns[1][3]) < 4) {
- msgcgi("r s", "secon. dns");
- return (WRUNKNOWN);
- }
- if (blocks[6].lines != 1
- || sscanf(macbuf, "%hhu%hhu%hhu%hhu%hhu%hhu", &data->mac[0],
- &data->mac[1], &data->mac[2], &data->mac[3], &data->mac[4],
- &data->mac[5]) < 6) {
- msgcgi("r a", "mac addr.");
- return (WRUNKNOWN);
+ /* Fuseau horaire. */
+
+ if (blocks[2].lines != 1 || sscanf(gmtbuf, "%d",
+ &cfg.current_time.tzhour) < 1) {
+ msgcgi("h G", "gmt");
+ return (WRUNKNOWN);
+ }
+ cfg.current_time.tzmin = 0;
+
+ /* Heure d'été (dst). */
+
+ if (blocks[3].lines != 1) {
+ msgcgi("h e", "dst");
+ return (WRUNKNOWN);
+ }
+ cfg.current_time.sum = sumbuf[0] ? 1 : 0;
+
+ /* Jour de la semaine. */
+
+ if (blocks[4].lines != 1 || blocks[5].lines != 1
+ || blocks[6].lines != 1 || blocks[7].lines != 1
+ || blocks[8].lines != 1 || blocks[9].lines != 1) {
+ msgcgi("g [1-7]", "day of week");
+ return (WRUNKNOWN);
+ }
+ cfg.current_time.dow = sembuf1[0] ? 0 : sembuf2[0] ? 1 :
+ sembuf3[0] ? 2 : sembuf4[0] ? 3 : sembuf5[0] ? 4 :
+ sembuf6[0] ? 5 : 6;
+
+ /* Mode DHCP activé ou non. */
+
+ if (blocks[10].lines != 1) {
+ msgcgi("r d", "dhcp enabled");
+ return (WRUNKNOWN);
+ }
+ cfg.more.ip.dhcp_enabled = dhcpbuf[0] ? 1 : 0;
+
+ /* IP fixe/courante. */
+
+ if (blocks[11].lines != 1 || sscanf(ipbuf, "%hhu%hhu%hhu%hhu",
+ &cfg.more.ip.ip[0], &cfg.more.ip.ip[1], &cfg.more.ip.ip[2],
+ &cfg.more.ip.ip[3]) < 4) {
+ msgcgi("r i", "current ip");
+ return (WRUNKNOWN);
+ }
+
+ /* Masque de sous-réseau en configuration fixe. */
+
+ if (blocks[12].lines != 1 || sscanf(msbuf, "%hhu%hhu%hhu%hhu",
+ &cfg.more.ip.mask[0], &cfg.more.ip.mask[1], &cfg.more.ip.mask[2],
+ &cfg.more.ip.mask[3]) < 4) {
+ msgcgi("r m", "netmask");
+ return (WRUNKNOWN);
+ }
+
+ /* Passerelle par défaut en configuration fixe. */
+
+ if (blocks[13].lines != 1 || sscanf(gwbuf, "%hhu%hhu%hhu%hhu",
+ &cfg.more.ip.gw[0], &cfg.more.ip.gw[1], &cfg.more.ip.gw[2],
+ &cfg.more.ip.gw[3]) < 4) {
+ msgcgi("r g", "gateway");
+ return (WRUNKNOWN);
+ }
+
+ /* Serveur DNS primaire. */
+
+ if (blocks[14].lines != 1 || sscanf(dpbuf, "%hhu%hhu%hhu%hhu",
+ &cfg.more.ip.dns1[0], &cfg.more.ip.dns1[1], &cfg.more.ip.dns1[2],
+ &cfg.more.ip.dns1[3]) < 4) {
+ msgcgi("r p", "primary dns");
+ return (WRUNKNOWN);
+ }
+
+ /* Serveur DNS secondaire. */
+
+ if (blocks[15].lines != 1 || sscanf(dsbuf, "%hhu%hhu%hhu%hhu",
+ &cfg.more.ip.dns2[0], &cfg.more.ip.dns2[1], &cfg.more.ip.dns2[2],
+ &cfg.more.ip.dns2[3]) < 4) {
+ msgcgi("r s", "secon. dns");
+ return (WRUNKNOWN);
+ }
+
+ /* Adresse MAC. */
+
+ if (blocks[16].lines != 1 || sscanf(macbuf, "%hhu%hhu%hhu%hhu%hhu%hhu",
+ &cfg.more.ip.mac[0], &cfg.more.ip.mac[1], &cfg.more.ip.mac[2],
+ &cfg.more.ip.mac[3], &cfg.more.ip.mac[4],
+ &cfg.more.ip.mac[5]) < 6) {
+ msgcgi("r a", "mac addr.");
+ return (WRUNKNOWN);
+ }
}
- *netp = &net;
+ *cfgp = &cfg;
return (WROK);
}
/* ---
- * Compteurs via TÉLÉINFO.
+ * Gestion des compteurs.
* --- */
-/* `getwestic()`: récupération des données concernant le compteur. */
-
-static int getwestic(wes_t *wes, int tic_id, westic_object_t **ticp)
+/* L'abstraction de serveur WES propose les compteurs suivants (avec
+ * identifiants) :
+ * [ 1] Compteur branché via télé-info 1 (TIC1).
+ * [ 2] Compteur branché via télé-info 2 (TIC2).
+ * [ 3] Pince ampèremétrique 1 (PCE1).
+ * [ 4] Pince ampèremétrique 2 (PCE2).
+ * [ 5] Pince ampèremétrique 3 (PCE3).
+ * [ 6] Pince ampèremétrique 4 (PCE4).
+ * [ 7] Compteur d'impulsions 1 (PLS1).
+ * [ 8] Compteur d'impulsions 2 (PLS2).
+ * [ 9] Compteur d'impulsions 3 (PLS3).
+ * [10] Compteur d'impulsions 4 (PLS4). */
+
+/* `getwestic()`: récupération de la configuration d'un compteur branché
+ * via télé-information. */
+
+static int getwestic(wes_t *wes, int tic_id, wesmeterflags_t flags,
+ wesmetercfg_t **ticp)
{
- static westic_object_t tic;
- static westiccfg_t *cfg;
- static westicdata_t *data;
- static char name[20];
+ static wesmetercfg_t cfg;
+ static char name[20], bdpvu[21], bdpvp[21];
- tic.free = NULL;
- cfg = &tic.cfg;
- data = &tic.data;
+ (void)flags;
+
+ cfg.free = NULL;
if (tic_id != 0 && tic_id != 1)
return (WROP);
+ cfg.type = WESMETERTYPE_TELEINFO;
+ cfg.what = WESMETERWHAT_ELEC;
+
{
- char isrd[5], abo[10], pror[5],
+ char isrd[5], prod2[5], abo[10], pror[5],
tarif0[10], tarif1[10], tarif2[10], tarif3[10],
- tarif4[10], tarif5[10], prod2[5],
- bdpve[5], bdpvh[10], bdpvm[10],
- adco[20], abotype[10], monotri[5], ptec[20],
- isousc[10], pa[10], ii0[10], ii1[10], ii2[10],
- im0[10], im1[10], im2[10], idx0[15], idx1[15],
- idx2[15], idx3[15], idx4[15], idx5[15];
+ tarif4[10], tarif5[10],
+ bdpve[5], bdpvh[10], bdpvm[10];
wescgi_t blocks[] = {
+ /* Nom donné via l'interface au compteur.
+ * `e n`: TIC1, `e N`: TIC2 */
+ WESCGI(tic_id ? "e N" : "e n", "%s", name, 20),
+
/* Selon si le compteur est lu (checked) ou non.
* `G t`: TIC1, `G T`: TIC2 */
WESCGI(tic_id ? "G T" : "G t", "%.1s", isrd, 5),
- /* Nom donné via l'interface au compteur.
- * `e n`: TIC1, `e N`: TIC2 */
- WESCGI(tic_id ? "e N" : "e n", "%s", name, 20),
+ /* Selon si l'on est en mode consommation ou production (pour
+ * le compteur 2 uniquement).
+ * `G C`: mode consommation (checked).
+ * `G p`: mode production (checked). */
+ WESCGI("G p", "%.1s", prod2, 5),
/* Coût fixe en euros du compteur. */
WESCGI(tic_id ? "C A" : "C a", "%0.2f", abo, 10),
@@ -450,12 +484,6 @@ static int getwestic(wes_t *wes, int tic_id, westic_object_t **ticp)
WESCGI(tic_id ? "C T4" : "C t4", "%0.5f", tarif4, 10),
WESCGI(tic_id ? "C T5" : "C t5", "%0.5f", tarif5, 10),
- /* Selon si l'on est en mode consommation ou production (pour
- * le compteur 2 uniquement).
- * `G C`: mode consommation (checked).
- * `G p`: mode production (checked). */
- WESCGI("G p", "%.1s", prod2, 5),
-
/* Si mode production, paramètres BDPV (pour le compteur 2
* uniquement).
* `H a`: activé (checked).
@@ -464,73 +492,47 @@ static int getwestic(wes_t *wes, int tic_id, westic_object_t **ticp)
* `H h`: heure d'envoi.
* `H m`: minute d'envoi. */
WESCGI("H a", "%.1s", bdpve, 5),
+ WESCGI("H i", "%s", bdpvu, 21),
+ WESCGI("H p", "%s", bdpvp, 21),
WESCGI("H h", "%d", bdpvh, 10),
- WESCGI("H m", "%d", bdpvm, 10),
-
- /* Numéro ADCO du compteur. */
- WESCGI(tic_id ? "e A" : "e a", "%s", adco, 20),
-
- /* Type d'abonnement.
- * - 0: BASE
- * - 1: Heure Creuse
- * - 2: EJP
- * - 3: TEMPO */
- WESCGI(tic_id ? "e D" : "e d", "%d", abotype, 10),
-
- /* Mode de l'entrée (mono ou triphasé).
- * - 0: inconnu
- * - 1: monophasé
- * - 3: triphasé */
- WESCGI(tic_id ? "I M" : "i M", "%d", monotri, 10),
-
- /* Période tarifaire en cours (TODO: format?). */
- WESCGI(tic_id ? "T P" : "T p", "%s", ptec, 20),
-
- /* Intensité souscrite (en A),
- * puissance apparente (en VA). */
- WESCGI(tic_id ? "e C" : "e c", "%d", isousc, 10),
- WESCGI(tic_id ? "I p" : "i p", "%d", pa, 10),
-
- /* Intensité instantanée pour chaque phase (en A). */
- WESCGI(tic_id ? "Ii0" : "ii0", "%d", ii0, 10),
- WESCGI(tic_id ? "Ii1" : "ii1", "%d", ii1, 10),
- WESCGI(tic_id ? "Ii2" : "ii2", "%d", ii2, 10),
-
- /* Intensité maximale pour chaque phase (en A). */
- WESCGI(tic_id ? "Im0" : "im0", "%d", im0, 10),
- WESCGI(tic_id ? "Im1" : "im1", "%d", im1, 10),
- WESCGI(tic_id ? "Im2" : "im2", "%d", im2, 10),
-
- /* Index 1 à 6 pour les compteurs. */
- WESCGI(tic_id ? "TI1" : "Ti1", "%s", idx0, 15),
- WESCGI(tic_id ? "TI2" : "Ti2", "%s", idx1, 15),
- WESCGI(tic_id ? "TI3" : "Ti3", "%s", idx2, 15),
- WESCGI(tic_id ? "TI4" : "Ti4", "%s", idx3, 15),
- WESCGI(tic_id ? "TI5" : "Ti5", "%s", idx4, 15),
- WESCGI(tic_id ? "TI6" : "Ti6", "%s", idx5, 15)
+ WESCGI("H m", "%d", bdpvm, 10)
};
- GETCGI(32, blocks)
+ GETCGI(16, blocks)
+
+ /* ---
+ * Décodage des éléments.
+ * --- */
- /* Options de base du compteur TELEINFO. */
+ /* Nom du compteur. */
if (blocks[0].lines != 1) {
- msgcgi("G [tT]", "teleinfo is read");
+ msgcgi("e [nN]", "teleinfo name");
return (WRUNKNOWN);
}
- cfg->is_read = isrd[0] ? 1 : 0;
+
+ cfg.name = name;
+
+ /* Le compteur est-il lu ? */
if (blocks[1].lines != 1) {
- msgcgi("e [nN]", "teleinfo name");
+ msgcgi("G [tT]", "teleinfo is read");
return (WRUNKNOWN);
}
+ cfg.is_read = isrd[0] ? 1 : 0;
+
+ /* Mode de consommation/production. */
- cfg->name = name;
+ if (blocks[2].lines != 1) {
+ msgcgi("G p", "prod cpt. 2");
+ return (WRUNKNOWN);
+ }
+ cfg.mode = tic_id && prod2[0] ? WESMETERMODE_PROD : WESMETERMODE_CONSO;
- /* Tarifs. */
+ /* Tarifs de base. */
if (blocks[2].lines != 1
- || sscanf(abo, "%lf", &cfg->abo) < 1) {
+ || sscanf(abo, "%lf", &cfg.fixed_cost) < 1) {
msgcgi("C [aA]", "fixed costs");
return (WRUNKNOWN);
}
@@ -539,7 +541,9 @@ static int getwestic(wes_t *wes, int tic_id, westic_object_t **ticp)
msgcgi("C p[12]", "prorata");
return (WRUNKNOWN);
}
- cfg->prorata = pror[0] ? 1 : 0;
+ cfg.prorata = pror[0] ? 1 : 0;
+
+ /* Tarifs détaillés. */
{
double tf0, tf1, tf2, tf3, tf4, tf5;
@@ -575,236 +579,198 @@ static int getwestic(wes_t *wes, int tic_id, westic_object_t **ticp)
return (WRUNKNOWN);
}
- cfg->tarif_base = tf0;
- cfg->tarif_hchp_hc = tf0;
- cfg->tarif_hchp_hp = tf1;
- cfg->tarif_tempo_hcjb = tf0;
- cfg->tarif_tempo_hpjb = tf1;
- cfg->tarif_tempo_hcjw = tf2;
- cfg->tarif_tempo_hpjw = tf3;
- cfg->tarif_tempo_hcjr = tf4;
- cfg->tarif_tempo_hpjr = tf5;
- cfg->tarif_ejp_hn = tf0;
- cfg->tarif_ejp_pm = tf1;
+ cfg.more.teleinfo.cost_base_th = tf0;
+ cfg.more.teleinfo.cost_hchp_hc = tf0;
+ cfg.more.teleinfo.cost_hchp_hp = tf1;
+ cfg.more.teleinfo.cost_tempo_hcjb = tf0;
+ cfg.more.teleinfo.cost_tempo_hpjb = tf1;
+ cfg.more.teleinfo.cost_tempo_hcjw = tf2;
+ cfg.more.teleinfo.cost_tempo_hpjw = tf3;
+ cfg.more.teleinfo.cost_tempo_hcjr = tf4;
+ cfg.more.teleinfo.cost_tempo_hpjr = tf5;
+ cfg.more.teleinfo.cost_ejp_hn = tf0;
+ cfg.more.teleinfo.cost_ejp_pm = tf1;
}
- /* Mode consommation/production (si compteur 2), connexion
- * avec le site BDPV. */
+ /* Configuration BDPV (si compteur 2, hardcodé dans le serveur WES),
+ * i.e. détails de connexion au site BDPV. */
if (tic_id == 0) {
- cfg->bdpv_hour = 0;
- cfg->bdpv_min = 0;
+ cfg.more.teleinfo.bdpv_enabled = 0;
+ cfg.more.teleinfo.bdpv_hour = 0;
+ cfg.more.teleinfo.bdpv_min = 0;
+ cfg.more.teleinfo.bdpv_username = "";
+ cfg.more.teleinfo.bdpv_password = "";
} else {
+ /* Selon si BDPV est activé ou non. */
+
if (blocks[10].lines != 1) {
- msgcgi("G p", "prod cpt. 2");
+ msgcgi("H a", "bdpv enabled");
return (WRUNKNOWN);
}
+ cfg.more.teleinfo.bdpv_enabled = bdpve[0] ? 1 : 0;
+
+ /* Utilisateur et mot de passe du compte BDPV. */
+
if (blocks[11].lines != 1) {
- msgcgi("H a", "bdpv enabled");
+ msgcgi("H i", "bdpv username");
+ return (WRUNKNOWN);
+ }
+ if (blocks[12].lines != 1) {
+ msgcgi("H p", "bdpv password");
return (WRUNKNOWN);
}
- if (blocks[12].lines != 1
- || sscanf(bdpvh, "%d", &cfg->bdpv_hour)) {
+ cfg.more.teleinfo.bdpv_username = bdpvu;
+ cfg.more.teleinfo.bdpv_password = bdpvp;
+
+ /* Heure et minute d'envoi. */
+
+ if (blocks[13].lines != 1 || sscanf(bdpvh, "%d",
+ &cfg.more.teleinfo.bdpv_hour)) {
msgcgi("H h", "bdpv send hour");
return (WRUNKNOWN);
}
- if (blocks[13].lines != 1
- || sscanf(bdpvm, "%d", &cfg->bdpv_min)) {
+ if (blocks[14].lines != 1 || sscanf(bdpvm, "%d",
+ &cfg.more.teleinfo.bdpv_min)) {
msgcgi("H m", "bdpv send min.");
return (WRUNKNOWN);
}
-
- cfg->mode = prod2[0] ? WESMODE_PROD : WESMODE_CONSO;
- if (cfg->mode == WESMODE_CONSO)
- cfg->bdpv_enabled = 0;
- else
- cfg->bdpv_enabled = bdpve[0] ? 1 : 0;
}
+ }
- /* En-têtes TELEINFO du compteur. */
+ *ticp = &cfg;
+ return (WROK);
+}
- data->is_plugged_in = 1;
- data->is_standing_by = 0; /* TODO: et si c'est le cas ? */
- if (blocks[14].lines != 1
- || (strcmp(adco, "Pas Dispo") && strlen(adco) != 12)) {
- msgcgi("e [aA]", "ADCO");
- return (WRUNKNOWN);
- }
+/* `getwesmeter()`: récupération de la configuration d'un compteur. */
- if (adco[0] == 'P')
- data->is_plugged_in = 0;
- else {
- int i;
+static int getwesmeter(wes_t *wes, int meter_id, wesmetertype_t expected,
+ wesmeterflags_t flags, wesmetercfg_t **meterp)
+{
+ switch (meter_id) {
+ case 1: case 2:
+ /* Compteurs branchés via télé-information numéro 0 à 1. */
- data->is_plugged_in = 1;
- for (i = 0; i < 12; i++) {
- if (!isdigit(adco[i])) {
- msgcgi("e [aA]", "ADCO character non digit");
- return (WRUNKNOWN);
- }
+ if (expected != WESMETERTYPE_TELEINFO)
+ return (WROP);
+ return (getwestic(wes, meter_id - 1, flags, meterp));
- data->adco[i] = (unsigned char)(adco[i] - '0');
- }
- }
+#if 0 /* TODO: fonctions associées */
+ case 3: case 4: case 5: case 6:
+ /* Pinces ampèremétriques numéro 0 à 3. */
- {
- int at;
+ if (expected != WESMETERTYPE_AMPER)
+ return (WROP);
+ return (getwespce(wes, meter_id - 3, flags, meterp));
- if (blocks[15].lines != 1
- || sscanf(abotype, "%d", &at) < 1
- || at < 0 || at > 3) {
- msgcgi("e [dD]", "sub. type");
- return (WRUNKNOWN);
- }
+ case 7: case 8: case 9: case 10:
+ /* Compteurs d'impulsions numéro 0 à 3. */
- switch (at) {
- case 0:
- data->tarif = WESTICTARIF_BASE;
- break;
- case 1:
- data->tarif = WESTICTARIF_HCHP;
- break;
- case 2:
- data->tarif = WESTICTARIF_EJP;
- break;
- case 3:
- data->tarif = WESTICTARIF_TEMPO;
- break;
- default:
- msgcgi("e [dD]", "sub. type");
- return (WRUNKNOWN);
- }
- }
+ if (expected != WESMETERTYPE_PULSE)
+ return (WROP);
+ return (getwespls(wes, meter_id - 7, flags, meterp));
+#endif
- {
- int mt;
+ default:
+ /* Numéro inconnu ! */
+ break;
+ }
- if (blocks[16].lines != 1
- || sscanf(monotri, "%d", &mt) < 1) {
- msgcgi("[iI] M", "phase mode");
- return (WRUNKNOWN);
- }
+ return (WRVAL);
+}
- switch (mt) {
- case 0:
- data->phases = 0;
- break;
- case 1:
- data->phases = 1;
- break;
- case 3:
- data->phases = 3;
- break;
- default:
- msgcgi("[iI] M", "phase mode");
- return (WRUNKNOWN);
- }
- }
+/* ---
+ * Listage des compteurs.
+ * --- */
- /* TODO: période tarifaire en cours */
- data->period = WESTICPERIOD_HN;
+struct wes_iter {
+ int current;
+ int left;
+};
- /* Intensité souscrite, puissance apparente. */
+/* `getwesmeteriter()`: prepare the iterator. */
- if (blocks[18].lines != 1
- || sscanf(isousc, "%u", &data->isousc) < 1) {
- msgcgi("e [cC]", "intens. souscrite");
- return (WRUNKNOWN);
- }
- if (blocks[19].lines != 1
- || sscanf(pa, "%u", &data->pa) < 1) {
- msgcgi("[iI] p", "puis. app.");
- return (WRUNKNOWN);
- }
+static int getwesmeteriter(wes_t *wes, wesmetertype_t type,
+ struct wes_iter **iterp)
+{
+ struct wes_iter *iter;
+ int cur, left;
+
+ (void)wes; /* mêmes compteurs pour tous les WES de ce type */
+
+ switch (type) {
+ case WESMETERTYPE_NONE:
+ cur = 1;
+ left = 10;
+ break;
+ case WESMETERTYPE_AMPER:
+ cur = 3;
+ left = 4;
+ break;
+ case WESMETERTYPE_PULSE:
+ cur = 7;
+ left = 4;
+ break;
+ case WESMETERTYPE_TELEINFO:
+ cur = 1;
+ left = 2;
+ break;
+ default:
+ cur = 0;
+ left = 0;
+ }
- /* Intensité instantanée pour chaque phase. */
+ if (!(iter = (*iterp = malloc(sizeof(*iter)))))
+ return (WRALLOC);
+ iter->current = cur;
+ iter->left = left;
- if (blocks[20].lines != 1
- || sscanf(ii0, "%u", &data->iinst[0]) < 1) {
- msgcgi("[iI]i0", "i. inst. 0");
- return (WRUNKNOWN);
- }
- if (blocks[21].lines != 1
- || sscanf(ii1, "%u", &data->iinst[1]) < 1) {
- msgcgi("[iI]i1", "i. inst. 1");
- return (WRUNKNOWN);
- }
- if (blocks[22].lines != 1
- || sscanf(ii2, "%u", &data->iinst[2]) < 1) {
- msgcgi("[iI]i2", "i. inst. 2");
- return (WRUNKNOWN);
- }
+ return (WROK);
+}
- /* Intensité maximale pour chaque phase. */
+/* `getwesmeternext()`: get the next meter. */
- if (blocks[23].lines != 1
- || sscanf(im0, "%u", &data->imax[0]) < 1) {
- msgcgi("[iI]m0", "i. max. 0");
- return (WRUNKNOWN);
- }
- if (blocks[24].lines != 1
- || sscanf(im1, "%u", &data->imax[1]) < 1) {
- msgcgi("[iI]m1", "i. max. 1");
- return (WRUNKNOWN);
- }
- if (blocks[25].lines != 1
- || sscanf(im2, "%u", &data->imax[2]) < 1) {
- msgcgi("[iI]m2", "i. max. 2");
- return (WRUNKNOWN);
- }
+static int getwesmeternext(struct wes_iter *iter, int *id,
+ wesmetertype_t *type)
+{
+ if (!iter->left)
+ return (WRITER);
+ *id = iter->current;
+ iter->current++;
+ iter->left--;
+
+ switch (*id) {
+ case 1: case 2:
+ *type = WESMETERTYPE_TELEINFO;
+ break;
+ case 3: case 4: case 5: case 6:
+ *type = WESMETERTYPE_AMPER;
+ break;
+ case 7: case 8: case 9: case 10:
+ *type = WESMETERTYPE_PULSE;
+ break;
+ default:
+ *type = WESMETERTYPE_NONE;
+ break;
+ }
- /* Index */
- {
- unsigned long ix0 = 0, ix1 = 0, ix2 = 0, ix3 = 0,
- ix4 = 0, ix5 = 0;
+ return (WROK);
+}
- if (blocks[26].lines != 1 || (strcmp(idx0, "Pas Dispo")
- && sscanf(idx0, "%lu", &ix0) < 1)) {
- msgcgi("T[iI]0", "index 0");
- return (WRUNKNOWN);
- }
- if (blocks[27].lines != 1 || (strcmp(idx1, "Pas Dispo")
- && sscanf(idx1, "%lu", &ix1) < 1)) {
- msgcgi("T[iI]1", "index 1");
- return (WRUNKNOWN);
- }
- if (blocks[28].lines != 1 || (strcmp(idx2, "Pas Dispo")
- && sscanf(idx2, "%lu", &ix2) < 1)) {
- msgcgi("T[iI]2", "index 2");
- return (WRUNKNOWN);
- }
- if (blocks[29].lines != 1 || (strcmp(idx3, "Pas Dispo")
- && sscanf(idx3, "%lu", &ix3) < 1)) {
- msgcgi("T[iI]3", "index 3");
- return (WRUNKNOWN);
- }
- if (blocks[30].lines != 1 || (strcmp(idx4, "Pas Dispo")
- && sscanf(idx4, "%lu", &ix4) < 1)) {
- msgcgi("T[iI]4", "index 4");
- return (WRUNKNOWN);
- }
- if (blocks[31].lines != 1 || (strcmp(idx5, "Pas Dispo")
- && sscanf(idx5, "%lu", &ix5) < 1)) {
- msgcgi("T[iI]5", "index 5");
- return (WRUNKNOWN);
- }
+static int skipwesmeters(struct wes_iter *iter, int number)
+{
+ if (number > iter->left)
+ number = iter->left;
+ iter->current += number;
+ iter->left -= number;
- data->index_base = ix0;
- data->index_hchp_hc = ix0;
- data->index_hchp_hp = ix1;
- data->index_tempo_hcjb = ix0;
- data->index_tempo_hpjb = ix1;
- data->index_tempo_hcjw = ix2;
- data->index_tempo_hpjw = ix3;
- data->index_tempo_hcjr = ix4;
- data->index_tempo_hpjr = ix5;
- data->index_ejp_hn = ix0;
- data->index_ejp_pm = ix1;
- }
- }
+ return (WROK);
+}
- *ticp = &tic;
+static int delwesmeteriter(struct wes_iter *iter)
+{
+ free(iter);
return (WROK);
}
@@ -813,10 +779,20 @@ static int getwestic(wes_t *wes, int tic_id, westic_object_t **ticp)
* --- */
static wesif_t ipif = {
- free_ip_wes,
- NULL,
- setwesids,
- getwestime, NULL,
- getwesnet, NULL,
- getwestic, NULL, NULL
+ WESTYPE_IP, free_ip_wes,
+
+ /* Interaction avec la configuration. */
+
+ getwescfg, NULL,
+
+ /* Interaction avec les compteurs. */
+
+ getwesmeter, NULL, NULL,
+
+ /* Listage des compteurs. */
+
+ (wesif_getmeteriter_t *)getwesmeteriter,
+ (wesif_getmeternext_t *)getwesmeternext,
+ (wesif_skipmeters_t *)skipwesmeters,
+ (wesif_delmeteriter_t *)delwesmeteriter
};
diff --git a/daemon/ip/internals.h b/daemon/ip/internals.h
index ff90563..0cdd6bb 100644
--- a/daemon/ip/internals.h
+++ b/daemon/ip/internals.h
@@ -90,13 +90,13 @@ typedef struct wescsv {
/* Élément de configuration. */
-typedef struct wescfg {
- struct wescfg *next;
+typedef struct wescfgkey {
+ struct wescfgkey *next;
size_t keysz; /* Taille de la clé de configuration */
size_t valsz; /* Taille de la valeur */
char data[];
-} wescfg_t;
+} wescfgkey_t;
/* Section de configuration.
* Une section contient à la fois :
@@ -107,7 +107,7 @@ typedef struct wescfg {
typedef struct wescfgsec {
struct wescfgsec *next;
- wescfg_t *child;
+ wescfgkey_t *child;
size_t keysz;
#if 0
size_t textsz;
diff --git a/daemon/server.c b/daemon/server.c
index 9ad048d..f551265 100644
--- a/daemon/server.c
+++ b/daemon/server.c
@@ -36,7 +36,22 @@
#include <weshd.h> /* définitions du protocole depuis `weshd.x` */
-#define REQADDR inet_ntoa(svc_getcaller(req->rq_xprt)->sin_addr)
+/* ---
+ * Get the string for an address, for logging.
+ * --- */
+
+static const char *addrstr(struct in6_addr *src)
+{
+ static char str[INET6_ADDRSTRLEN + 1] = {0};
+
+ return (inet_ntop(AF_INET6, src, str, sizeof(str)));
+}
+
+#define REQADDR addrstr(&svc_getcaller(req->rq_xprt)->sin6_addr)
+
+/* ---
+ * Macro to get the WES resource from the ID.
+ * --- */
#define GETWES(ID, RET, RESP) { \
int getwes_err; \
@@ -65,87 +80,105 @@ static weslist_t *list;
static jmp_buf endjmp;
/* ---
+ * Requêtes de base.
+ * --- */
+
+/* `weshd_null_1_svc()`: Ne rien faire (sert à pinger le service). */
+
+void *weshd_null_1_svc(void *argp, struct svc_req *req)
+{
+ static char val[4] = "ok!";
+
+ (void)argp;
+ (void)req;
+ return ((void*)&val);
+}
+
+/* ---
* Gestion des ressources existentes.
* --- */
/* `gather_1_svc()`: Création de ressource, ou récupération de ressource
* existante. */
-wespret_with_id_t *gather_1_svc(wespregopts_t *args,
+wespret_with_id_t *gather_1_svc(wespoptions_t *args,
struct svc_req *req)
{
static wespret_with_id_t resp;
- wescreatedata_t data;
- int (*addfunc)(weslist_t *, wes_t **, wescreatedata_t *);
const unsigned char *ip;
- wesaddr_t *addr; int err;
+ wesaddr_t addr; int err;
+ wespoptions_ip_t *ipopts;
wes_t *wes;
resp.ret = WESPRET_INT;
msg((wlnotice, "(%s) register server", REQADDR));
- /* On vérifie le type de ressource WES à créer. */
-
switch (args->type) {
- case WESPREGTYPE_DUMMY:
- addfunc = &add_dummy_wes;
- break;
- case WESPREGTYPE_IP:
- addfunc = &add_ip_wes;
+ case WESPTYPE_DUMMY:
+ /* On crée et ajoute directement la ressource de type dummy,
+ * sans faire de chichis. */
+
+ err = add_dummy_wes(list, &wes);
break;
- default:
- resp.ret = WESPRET_VAL;
- return (&resp);
- }
- /* On prépare les données de création en fonction de ce qui est envoyé. */
+ case WESPTYPE_IP:
+ /* On prépare l'adresse IP. */
- addr = &data.addr;
- switch (args->ip.type) {
- case WESPIPTYPE_4:
- ip = args->ip.ipv4;
+ ipopts = &args->wespoptions_t_u.ip;
- msg((wlnotice, "(%s) using IPv4 address %hhu.%hhu.%hhu.%hhu", \
- REQADDR, ip[0], ip[1], ip[2], ip[3]));
+ switch (ipopts->addr.type) {
+ case WESPIPTYPE_4:
+ ip = ipopts->addr.wespip_t_u.addr4;
- addr->type = WINET;
- addr->data.inet.has = HASIPv4;
- memcpy(addr->data.inet.ipv4, ip, 4);
+ msg((wlnotice, "(%s) using IPv4 address %hhu.%hhu.%hhu.%hhu",
+ REQADDR, ip[0], ip[1], ip[2], ip[3]));
- break;
+ addr.type = WINET;
+ addr.data.inet.has = HASIPv4;
+ memcpy(addr.data.inet.ipv4, ip, 4);
- case WESPIPTYPE_6:
- ip = args->ip.ipv6;
+ break;
- msg((wlnotice, "(%s) using IPv6 address "
- "%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:"
- "%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX",
- REQADDR, ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7],
- ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15]));
+ case WESPIPTYPE_6:
+ ip = ipopts->addr.wespip_t_u.addr6;
- addr->type = WINET;
- addr->data.inet.has = HASIPv6;
- memcpy(addr->data.inet.ipv6, ip, 16);
+ msg((wlnotice, "(%s) using IPv6 address "
+ "%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:"
+ "%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX",
+ REQADDR, ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6],
+ ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13],
+ ip[14], ip[15]));
- break;
+ addr.type = WINET;
+ addr.data.inet.has = HASIPv6;
+ memcpy(addr.data.inet.ipv6, ip, 16);
- default:
- addr->type = WNONET;
+ break;
+
+ default:
+ addr.type = WNONET;
+ break;
+ }
+
+ /* On définit les identifiants. */
+
+ err = add_ip_wes(list, &wes, &addr,
+ ipopts->http_username, ipopts->http_password,
+ ipopts->ftp_username, ipopts->ftp_password);
break;
- }
- /* On définit les identifiants. */
+ default:
+ /* Je ne connais pas ce type de WES. */
- data.http_username = args->http_username;
- data.http_password = args->http_password;
- data.ftp_username = args->ftp_username;
- data.ftp_password = args->ftp_password;
+ resp.ret = WESPRET_VAL;
+ return (&resp);
+ }
- /* On ajoute la ressource en utilisant la fonction dédiée de l'interface
- * choisie par le client. */
+ /* On regarde l'erreur retournée par la fonction dédiée de création et
+ * d'ajout à la liste. */
- switch ((err = (*addfunc)(list, &wes, &data))) {
+ switch (err) {
case WROK:
msg((wlinfo, "success in creating the resource!"));
break;
@@ -199,366 +232,603 @@ wespret_t *unregister_1_svc(wespid_t *id, struct svc_req *req)
}
/* ---
- * Gestion du nom d'hôte du serveur WES.
+ * Récupération de la configuration du serveur WES.
* --- */
-/* `get_host_name_1_svc()`: Récupération du nom d'hôte. */
-
-wespret_with_hostname_t *get_host_name_1_svc(wespid_t *id, struct svc_req *req)
-{
- static wespret_with_hostname_t resp;
- wes_t *wes;
-
- msg((wlnotice, "(%s) get hostname on server %d", REQADDR, *id));
-
- GETWES(*id, resp.ret, &resp)
-
- resp.ret = WESPRET_OK;
- resp.hostname = wes->name;
- return (&resp);
-}
-
-/* `set_host_name_1_svc()`: Définition du nom d'hôte. */
+/* `get_1_svc()`: Récupération de la configuration d'un serveur WES. */
-wespret_t *set_host_name_1_svc(wespid_with_hostname_t *args,
+wespret_with_wes_t *get_1_svc(wespid_with_wes_flags_t *args,
struct svc_req *req)
{
- static wespret_t ret;
- int err; wes_t *wes;
- char *name;
-
- msg((wlnotice, "(%s) set hostname on server %d", REQADDR, args->id));
- ret = WESPRET_INT;
+ static wespret_with_wes_t resp;
+ wescfg_t cfg, *cfgobj;
+ wes_t *wes; int err;
+ wescfgflags_t flags;
+ wespdt_t *pdt;
+ wespipmore_t *ipmoar;
- GETWES(args->id, ret, &ret)
+ msg((wlnotice, "(%s) get server %d config", REQADDR, args->id));
- /* Validation du hostname à définir. */
+ /* Récupération du WES. */
- if ((err = prep_valid_name(&name, args->hostname))) switch (err) {
- case WRVAL:
- ret = WESPRET_VAL;
- return (&ret);
+ GETWES(args->id, resp.ret, &resp)
+ /* On convertit les flags du protocole au format interne (au cas où
+ * les deux diffèrent, ce qui n'est pas le cas au moment où j'écris
+ * ce bout de code). */
+
+ flags = 0;
+ if (args->to_get & WESP_NAME)
+ flags |= WESCFG_NAME;
+ if (args->to_get & WESP_TIME)
+ flags |= WESCFG_TIME;
+
+ switch (wes->iface->type) {
+ case WESTYPE_IP:
+ if (args->to_get & WESP_DHCP)
+ flags |= WESCFG_DHCP;
+ if (args->to_get & WESP_IP)
+ flags |= WESCFG_IP;
+ if (args->to_get & WESP_MASK)
+ flags |= WESCFG_MASK;
+ if (args->to_get & WESP_GW)
+ flags |= WESCFG_GW;
+ if (args->to_get & WESP_DNS1)
+ flags |= WESCFG_DNS1;
+ if (args->to_get & WESP_DNS2)
+ flags |= WESCFG_DNS2;
+ if (args->to_get & WESP_MAC)
+ flags |= WESCFG_MAC;
+ break;
default:
- return (&ret);
+ break;
}
- msg((wlinfo, "hostname is '%s'", name));
+ /* Appel de la procédure correspondant à l'interface. */
- /* Mettre à jour via l'interface. */
+ switch ((err = (*wes->iface->getcfg)(wes, flags, &cfgobj))) {
+ case WROK:
+ break;
- if (!wes->iface->setname) {
- ret = WESPRET_IMP;
- free_name(name);
- return (&ret);
+ default:
+ msg((wlerror, "getcfg error: %s", error_string(err)));
+ resp.ret = WESPRET_INT;
+ return (&resp);
}
- if ((err = (*wes->iface->setname)(wes, name))) {
- free_name(name);
- ret = WESPRET_INT;
- return (&ret);
+ /* Décodage. */
+
+ memcpy(&cfg, cfgobj, sizeof(cfg));
+ correct_cfg(wes, &cfg, flags);
+
+ resp.wes.name = wes->name;
+ pdt = &resp.wes.current_time;
+ pdt->year = cfg.current_time.year;
+ pdt->mon = cfg.current_time.mon;
+ pdt->dom = cfg.current_time.dom;
+ pdt->hour = cfg.current_time.hour;
+ pdt->min = cfg.current_time.min;
+ pdt->sec = cfg.current_time.sec;
+ pdt->dow = cfg.current_time.dow;
+ pdt->tzhour = cfg.current_time.tzhour;
+ pdt->tzmin = cfg.current_time.tzmin;
+ pdt->dst = cfg.current_time.sum;
+
+ switch (wes->iface->type) {
+ case WESTYPE_DUMMY:
+ resp.wes.more.type = WESPTYPE_DUMMY;
+ break;
+ case WESTYPE_IP:
+ resp.wes.more.type = WESPTYPE_IP;
+ ipmoar = &resp.wes.more.wespmore_t_u.ip;
+ ipmoar->dhcp_enabled = cfg.more.ip.dhcp_enabled;
+ memcpy(ipmoar->ip, cfg.more.ip.ip, 4);
+ memcpy(ipmoar->mask, cfg.more.ip.mask, 4);
+ memcpy(ipmoar->gw, cfg.more.ip.gw, 4);
+ memcpy(ipmoar->dns1, cfg.more.ip.dns1, 4);
+ memcpy(ipmoar->dns2, cfg.more.ip.dns2, 4);
+ memcpy(ipmoar->mac, cfg.more.ip.mac, 6);
+ break;
+ default:
+ msg((wlerror, "invalid iftype: %d", wes->iface->type));
+ resp.ret = WESPRET_INT;
+ set_obj_to_free(wes, cfgobj);
+ return (&resp);
}
- /* Tout a réussi, on définit le nom de la ressource. */
-
- assign_name(wes, name);
+ /* Tout est bien qui finit bien ! */
- ret = WESPRET_OK;
- return (&ret);
+ resp.ret = WESPRET_OK;
+ set_obj_to_free(wes, cfgobj);
+ return (&resp);
}
-/* ---
- * Gestion des identifiants du serveur WES.
- * --- */
-
-/* `set_http_ids_1_svc()`: Définition des identifiants HTTP. */
+/* `set_1_svc()`: Définition de la configuration d'un serveur WES. */
-wespret_t *set_http_ids_1_svc(wespid_with_ids_t *args, struct svc_req *req)
+wespret_t *set_1_svc(wespid_with_wes_t *args, struct svc_req *req)
{
static wespret_t ret;
+ wes_t *wes; wescfg_t cfg;
+ wescfgflags_t setflags;
+ wespipmore_t *ipmoar;
+ int err;
- msg((wlnotice, "(%s) set http ids on server %d", REQADDR, args->id));
-
- ret = WESPRET_IMP;
- return (&ret);
-}
-
-/* `set_ftp_ids_1_svc()`: Définition des identifiants FTP. */
-
-wespret_t *set_ftp_ids_1_svc(wespid_with_ids_t *args, struct svc_req *req)
-{
- static wespret_t ret;
+ msg((wlnotice, "(%s) set server %d config", REQADDR, args->id));
- msg((wlnotice, "(%s) set ftp ids on server %d", REQADDR, args->id));
+ /* Récupération du WES. */
- ret = WESPRET_IMP;
- return (&ret);
-}
+ GETWES(args->id, ret, &ret)
-/* ---
- * Gestion de l'heure du serveur WES.
- * --- */
+ /* Préparation des arguments,
+ * avec gestion des drapeaux. */
-/* `get_date_time_1_svc()`: Récupération de l'horodate. */
+ ret = WESPRET_VAL;
-wespret_with_datetime_t *get_date_time_1_svc(wespid_t *id, struct svc_req *req)
-{
- static wespret_with_datetime_t resp;
- wes_t *wes; westime_object_t *dt;
+ cfg.free = NULL;
+ setflags = 0;
- msg((wlnotice, "(%s) get datetime from server %d", REQADDR, *id));
+ if (args->wes.to_set & WESP_NAME)
+ setflags |= WESCFG_NAME;
+ if (args->wes.to_set & WESP_TIME)
+ setflags |= WESCFG_TIME;
- resp.ret = WESPRET_INT;
+ switch (wes->iface->type) {
+ case WESTYPE_DUMMY:
+ case WESTYPE_NONE:
+ if (args->wes.more.type != WESPTYPE_DUMMY)
+ return (&ret);
+ break;
- GETWES(*id, resp.ret, &resp)
+ case WESTYPE_IP:
+ if (args->wes.more.type != WESPTYPE_IP)
+ return (&ret);
+
+ if (args->wes.to_set & WESP_DHCP)
+ setflags |= WESCFG_DHCP;
+ if (args->wes.to_set & WESP_MASK)
+ setflags |= WESCFG_MASK;
+ if (args->wes.to_set & WESP_IP)
+ setflags |= WESCFG_IP;
+ if (args->wes.to_set & WESP_GW)
+ setflags |= WESCFG_GW;
+ if (args->wes.to_set & WESP_DNS1)
+ setflags |= WESCFG_DNS1;
+ if (args->wes.to_set & WESP_DNS2)
+ setflags |= WESCFG_DNS2;
+
+ ipmoar = &args->wes.more.wespmore_t_u.ip;
+ cfg.more.ip.dhcp_enabled = ipmoar->dhcp_enabled;
+ memcpy(cfg.more.ip.ip, ipmoar->ip, 4);
+ memcpy(cfg.more.ip.mask, ipmoar->mask, 4);
+ memcpy(cfg.more.ip.gw, ipmoar->gw, 4);
+ memcpy(cfg.more.ip.dns1, ipmoar->dns1, 4);
+ memcpy(cfg.more.ip.dns2, ipmoar->dns2, 4);
+ break;
+ }
- /* Extraction via l'interface. */
+ /* Appel à la fonction associée de l'interface. */
- if (!wes->iface->gettime) {
- resp.ret = WESPRET_IMP;
- return (&resp);
+ if (!wes->iface->setcfg) {
+ ret = WESPRET_IMP;
+ return (&ret);
}
- switch ((*wes->iface->gettime)(wes, &dt)) {
+ switch ((err = (*wes->iface->setcfg)(wes, setflags, &cfg))) {
case WROK:
break;
-
- case WRNOHOST:
- resp.ret = WESPRET_CON;
- return (&resp);
-
default:
- resp.ret = WESPRET_INT;
- return (&resp);
+ msg((wlerror, "error while setting config: %s", error_string(err)));
+ break;
}
- /* Conversion en les données du protocole. */
-
- resp.dt.year = dt->cfg.dt.year;
- resp.dt.mon = dt->cfg.dt.mon;
- resp.dt.dom = dt->cfg.dt.dom;
- resp.dt.hour = dt->cfg.dt.hour;
- resp.dt.min = dt->cfg.dt.min;
- resp.dt.sec = dt->cfg.dt.sec;
- resp.dt.dow = dt->cfg.dt.dow;
- resp.dt.sum = dt->cfg.dt.sum;
- resp.dt.tz = dt->cfg.dt.tzhour * 60 + dt->cfg.dt.tzmin;
-
- /* Tout est bien qui finit bien ! */
+ /* On est bons ! */
- msg((wlinfo, "datetime gathered successfully"));
-
- set_obj_to_free(wes, dt);
- resp.ret = WESPRET_OK;
- return (&resp);
+ ret = WESPRET_OK;
+ return (&ret);
}
-/* `set_date_time_1_svc()`: Définition de l'horodate. */
+/* `query_wes_1_svc()`: recherche et listage de serveurs WES. */
-wespret_t *set_date_time_1_svc(wespid_with_datetime_t *args,
+wespret_with_wes_list_t *query_wes_1_svc(wespquery_t *args,
struct svc_req *req)
{
- static wespret_t ret;
+ static wespret_with_wes_list_t resp;
- msg((wlnotice, "(%s) set datetime on server %d", REQADDR, args->id));
+ msg((wlnotice, "(%s) query servers", REQADDR));
- ret = WESPRET_IMP;
- return (&ret);
+ /* TODO */
+ (void)args;
+
+ resp.ret = WESPRET_IMP;
+ return (&resp);
}
/* ---
- * Gestion de l'aspect réseau du serveur WES.
+ * Gestion des compteurs.
* --- */
-/* `get_network_1_svc()`: Récupération des paramètres réseau. */
+/* `get_meter_1_svc()`: Récupération de la configuration d'un compteur. */
-wespret_with_net_t *get_network_1_svc(wespid_t *id, struct svc_req *req)
+wespret_with_meter_t *get_meter_1_svc(wespid_with_meter_id_t *args,
+ struct svc_req *req)
{
- static wespret_with_net_t resp; wesnet_object_t *net;
- wes_t *wes; int err;
+ static wespret_with_meter_t resp;
+ wes_t *wes;
+ wesmetertype_t expected_type;
+ wesmeterflags_t flags;
+ wesmetercfg_t *cfg;
+ wesif_getmeter_t *getmeter;
+ int ret;
+
+ msg((wlnotice, "(%s) get meter %d config from server %d",
+ REQADDR, args->meter_id, args->id));
+
+ switch (args->expected_type) {
+ case WESPMETERTYPE_NONE:
+ expected_type = WESMETERTYPE_NONE;
+ break;
+ case WESPMETERTYPE_AMPER:
+ expected_type = WESMETERTYPE_AMPER;
+ break;
+ case WESPMETERTYPE_PULSE:
+ expected_type = WESMETERTYPE_PULSE;
+ break;
+ case WESPMETERTYPE_TELEINFO:
+ expected_type = WESMETERTYPE_TELEINFO;
+ break;
+ default:
+ resp.ret = WESPRET_IMP;
+ return (&resp);
+ }
- msg((wlnotice, "(%s) get network info from server %d", REQADDR, *id));
- resp.ret = WESPRET_INT;
+ /* Récupération du WES. */
+
+ GETWES(args->id, resp.ret, &resp)
+
+ /* Préparation des arguments. */
+
+ flags = 0;
+ if (args->to_get & WESPMETER_NAME)
+ flags |= WESMETER_NAME;
+ if (args->to_get & WESPMETER_READ)
+ flags |= WESMETER_READ;
+ if (args->to_get & WESPMETER_MODE)
+ flags |= WESMETER_MODE;
+ if (args->to_get & WESPMETER_WHAT)
+ flags |= WESMETER_WHAT;
+ if (args->to_get & WESPMETER_TYPE)
+ flags |= WESMETER_TYPE;
+ if (args->to_get & WESPMETER_FIXED_COSTS)
+ flags |= WESMETER_FIXED_COSTS;
+ if (args->to_get & WESPMETER_PRORATA)
+ flags |= WESMETER_PRORATA;
+
+ switch (expected_type) {
+ case WESMETERTYPE_NONE:
+ break;
- GETWES(*id, resp.ret, &resp)
+ case WESMETERTYPE_AMPER:
+ if (args->to_get & WESPMETER_COST)
+ flags |= WESMETER_COST;
+ if (args->to_get & WESPMETER_VOLTAGE)
+ flags |= WESMETER_VOLTAGE;
+ break;
+
+ case WESMETERTYPE_PULSE:
+ if (args->to_get & WESPMETER_COST)
+ flags |= WESMETER_COST;
+ if (args->to_get & WESPMETER_METHOD)
+ flags |= WESMETER_METHOD;
+ if (args->to_get & WESPMETER_GROUP)
+ flags |= WESMETER_GROUP;
+ break;
- /* Extraction depuis l'interface. */
+ case WESMETERTYPE_TELEINFO:
+ if (args->to_get & WESPMETER_COSTS_BASE)
+ flags |= WESMETER_COSTS_BASE;
+ if (args->to_get & WESPMETER_COSTS_HCHP)
+ flags |= WESMETER_COSTS_HCHP;
+ if (args->to_get & WESPMETER_COSTS_TEMPO)
+ flags |= WESMETER_COSTS_TEMPO;
+ if (args->to_get & WESPMETER_COSTS_EJP)
+ flags |= WESMETER_COSTS_EJP;
+ if (args->to_get & WESPMETER_BDPV_ENABLED)
+ flags |= WESMETER_BDPV_ENABLED;
+ if (args->to_get & WESPMETER_BDPV_IDS)
+ flags |= WESMETER_BDPV_IDS;
+ if (args->to_get & WESPMETER_BDPV_TIME)
+ flags |= WESMETER_BDPV_TIME;
+ break;
+ }
- if (!wes->iface->getnet) {
+ getmeter = wes->iface->getmeter;
+ if (!getmeter) {
resp.ret = WESPRET_IMP;
return (&resp);
}
- switch ((err = (*wes->iface->getnet)(wes, &net))) {
+ ret = (*getmeter)(wes, args->meter_id, expected_type, flags, &cfg);
+ switch (ret) {
case WROK:
break;
-
- case WRNOHOST:
- resp.ret = WESPRET_CON;
- return (&resp);
-
default:
- msg((wlerror, "if error occurred: %s", error_string(err)));
+ msg((wlerror, "could not get meter cfg: %s", error_string(ret)));
resp.ret = WESPRET_INT;
return (&resp);
}
- /* On convertit ça dans la structure de données du protocole. */
-
- resp.cfg.enable_dhcp = net->cfg.dhcp_enabled;
- memcpy(resp.cfg.ip, net->cfg.ip, 4);
- memcpy(resp.cfg.mask, net->cfg.mask, 4);
- memcpy(resp.cfg.gw, net->cfg.gw, 4);
- memcpy(resp.cfg.dns1, net->cfg.ns[0], 4);
- memcpy(resp.cfg.dns2, net->cfg.ns[1], 4);
- memcpy(resp.data.mac, net->data.mac, 6);
+ correct_meter(wes, cfg, expected_type, flags);
+
+ /* Traduction en le format du protocole. */
+
+ {
+ wespmeter_t *r;
+ wespmetermore_amper_t *amp;
+ wespmetermore_pulse_t *pul;
+ wespmetermore_teleinfo_t *tic;
+
+ r = &resp.meter;
+ r->name = cfg->name;
+ r->rd = cfg->is_read;
+ r->fixed_cost = cfg->fixed_cost;
+ r->prorata = cfg->prorata;
+
+ switch (cfg->mode) {
+ case WESMETERMODE_CONSO:
+ r->mode = WESPMETERMODE_CONSO;
+ break;
+ case WESMETERMODE_PROD:
+ r->mode = WESPMETERMODE_PROD;
+ break;
+ }
+
+ switch (cfg->what) {
+ case WESMETERWHAT_UNKNOWN:
+ r->what = WESPMETERWHAT_UNKNOWN;
+ break;
+ case WESMETERWHAT_WATER:
+ r->what = WESPMETERWHAT_WATER;
+ break;
+ case WESMETERWHAT_GAS:
+ r->what = WESPMETERWHAT_GAS;
+ break;
+ case WESMETERWHAT_ELEC:
+ r->what = WESPMETERWHAT_ELEC;
+ break;
+ case WESMETERWHAT_FUEL:
+ r->what = WESPMETERWHAT_FUEL;
+ break;
+ }
+
+ switch (cfg->type) {
+ case WESMETERTYPE_NONE:
+ r->more.type = WESPMETERTYPE_NONE;
+ break;
+ case WESMETERTYPE_AMPER:
+ r->more.type = WESPMETERTYPE_AMPER;
+ amp = &r->more.wespmetermore_t_u.amper;
+
+ amp->voltage = cfg->more.amper.voltage;
+ amp->cost = cfg->more.amper.cost;
+ break;
+ case WESMETERTYPE_PULSE:
+ r->more.type = WESPMETERTYPE_PULSE;
+ pul = &r->more.wespmetermore_t_u.pulse;
+
+ pul->group_size = cfg->more.pulse.group_size;
+ pul->cost = cfg->more.pulse.cost;
+
+ switch (cfg->more.pulse.method) {
+ case WESPLSMETHOD_ILS:
+ pul->method = WESPPLSMETHOD_ILS;
+ break;
+ case WESPLSMETHOD_ELEC:
+ pul->method = WESPPLSMETHOD_ELEC;
+ break;
+ }
+
+ break;
+ case WESMETERTYPE_TELEINFO:
+ r->more.type = WESPMETERTYPE_TELEINFO;
+ tic = &r->more.wespmetermore_t_u.teleinfo;
+
+ tic->cost_base_th = cfg->more.teleinfo.cost_base_th;
+ tic->cost_hchp_hc = cfg->more.teleinfo.cost_hchp_hc;
+ tic->cost_hchp_hp = cfg->more.teleinfo.cost_hchp_hp;
+ tic->cost_tempo_hcjb = cfg->more.teleinfo.cost_tempo_hcjb;
+ tic->cost_tempo_hpjb = cfg->more.teleinfo.cost_tempo_hpjb;
+ tic->cost_tempo_hcjw = cfg->more.teleinfo.cost_tempo_hcjw;
+ tic->cost_tempo_hpjw = cfg->more.teleinfo.cost_tempo_hpjw;
+ tic->cost_tempo_hcjr = cfg->more.teleinfo.cost_tempo_hcjr;
+ tic->cost_tempo_hpjr = cfg->more.teleinfo.cost_tempo_hpjr;
+ tic->cost_ejp_hn = cfg->more.teleinfo.cost_ejp_hn;
+ tic->cost_ejp_pm = cfg->more.teleinfo.cost_ejp_pm;
+
+ tic->bdpv_enabled = cfg->more.teleinfo.bdpv_enabled;
+ tic->bdpv_hour = cfg->more.teleinfo.bdpv_hour;
+ tic->bdpv_min = cfg->more.teleinfo.bdpv_min;
+ tic->bdpv_username = cfg->more.teleinfo.bdpv_username;
+ tic->bdpv_password = cfg->more.teleinfo.bdpv_password;
+ break;
+ }
+ }
- /* La réponse est bonne. */
+ /* Tout va bien ! */
resp.ret = WESPRET_OK;
- set_obj_to_free(wes, net);
+ set_obj_to_free(wes, cfg);
return (&resp);
}
-/* `set_network_1_svc()`: Définition des paramètres réseau. */
+/* `set_meter_1_svc()`: Définition de la configuration d'un compteur. */
-wespret_t *set_network_1_svc(wespid_with_net_t *args, struct svc_req *req)
+wespret_t *set_meter_1_svc(wespid_with_meter_t *args, struct svc_req *req)
{
static wespret_t ret;
- msg((wlnotice, "(%s) set network config on server %d", REQADDR, args->id));
+ msg((wlnotice, "(%s) set meter %d config on server %d",
+ REQADDR, args->meter_id, args->id));
+
+ /* TODO */
ret = WESPRET_IMP;
return (&ret);
}
-/* ---
- * Gestion du TÉLÉINFO.
- * --- */
+/* `get_meter_data_1_svc()`: Récupération des valeurs d'un compteur. */
+
+wespret_with_meter_data_t *get_meter_data_1_svc(
+ wespid_with_meter_id_and_span_t *args, struct svc_req *req)
+{
+ static wespret_with_meter_data_t resp;
+
+ msg((wlnotice, "(%s) get meter %d values from server %d",
+ REQADDR, args->meter_id, args->id));
-/* `get_tic_1_svc()`: Récupération de la configuration et des données
- * immédiates d'un compteur branché via TÉLÉINFO. */
+ /* TODO */
-wespret_with_tic_t *get_tic_1_svc(wespid_with_tic_id_t *args,
+ resp.ret = WESPRET_IMP;
+ return (&resp);
+}
+
+/* `query_meters_1_svc()`: Recherche de compteurs. */
+
+wespret_with_meter_list_t *query_meters_1_svc(wespid_with_meter_query_t *args,
struct svc_req *req)
{
- static wespret_with_tic_t resp;
- westic_object_t *tic; wes_t *wes;
- int err;
+ static wespret_with_meter_list_t resp;
+ wespmeter_list_element_t results[10];
+ int ret, meter_id;
+ wesmetertype_t meter_type;
+ wespmetertype_t meter_ptype;
+ wes_t *wes;
+ void *iter;
- msg((wlnotice, "(%s) get teleinfo %d info from server %d", REQADDR,
- args->tic_id, args->id));
- resp.ret = WESPRET_INT;
+ msg((wlnotice, "(%s) query meters on server %d",
+ REQADDR, args->id));
+
+ /* Vérification des paramètres */
- /* On vérifie si le numéro du compteur est bon. */
+ resp.ret = WESPRET_VAL;
+ resp.meters.meters_val = results;
+ resp.meters.meters_len = 0;
+
+ if (args->offset < 0 || args->offset > 32766
+ || args->count < 1 || args->count > 10)
+ return (&resp);
+ switch (args->of_type) {
+ case WESPMETERTYPE_NONE:
+ meter_type = WESMETERTYPE_NONE;
+ break;
+ case WESPMETERTYPE_AMPER:
+ meter_type = WESMETERTYPE_AMPER;
+ break;
+ case WESPMETERTYPE_PULSE:
+ meter_type = WESMETERTYPE_PULSE;
+ break;
+ case WESPMETERTYPE_TELEINFO:
+ meter_type = WESMETERTYPE_TELEINFO;
+ break;
+ default:
+ return (&resp);
+ }
+
+ /* Récupération du WES. */
GETWES(args->id, resp.ret, &resp)
- /* On récupère les données. */
+ /* Création de l'itérateur. */
- if (!wes->iface->gettic) {
+ if (!wes->iface->getmeteriter || !wes->iface->getmeternext
+ || !wes->iface->skipmeters) {
resp.ret = WESPRET_IMP;
return (&resp);
}
- switch ((err = (*wes->iface->gettic)(wes, args->tic_id, &tic))) {
- case WROK:
+ switch ((ret = (*wes->iface->getmeteriter)(wes, meter_type, &iter))) {
+ case 0:
break;
- case WRNOHOST:
- resp.ret = WESPRET_CON;
- return (&resp);
-
default:
- msg((wlerror, "tic error: %s", error_string(err)));
+ msg((wlerror, "could not get meter iterator: %s", error_string(ret)));
+ resp.ret = WESPRET_INT;
return (&resp);
}
- /* Conversion. */
-
- resp.cfg.read = tic->cfg.is_read;
- resp.cfg.name = tic->cfg.name;
- resp.cfg.mode = tic->cfg.mode;
- resp.cfg.abo = tic->cfg.abo;
- resp.cfg.prorata = tic->cfg.prorata;
- resp.cfg.tarif_base = tic->cfg.tarif_base;
- resp.cfg.tarif_hchp_hc = tic->cfg.tarif_hchp_hc;
- resp.cfg.tarif_hchp_hp = tic->cfg.tarif_hchp_hp;
- resp.cfg.tarif_tempo_hcjb = tic->cfg.tarif_tempo_hcjb;
- resp.cfg.tarif_tempo_hpjb = tic->cfg.tarif_tempo_hpjb;
- resp.cfg.tarif_tempo_hcjw = tic->cfg.tarif_tempo_hcjw;
- resp.cfg.tarif_tempo_hpjw = tic->cfg.tarif_tempo_hpjw;
- resp.cfg.tarif_tempo_hcjr = tic->cfg.tarif_tempo_hcjr;
- resp.cfg.tarif_tempo_hpjr = tic->cfg.tarif_tempo_hpjr;
- resp.cfg.tarif_ejp_hn = tic->cfg.tarif_ejp_hn;
- resp.cfg.tarif_ejp_pm = tic->cfg.tarif_ejp_pm;
- resp.cfg.bdpv_enabled = tic->cfg.bdpv_enabled;
- resp.cfg.bdpv_hour = tic->cfg.bdpv_hour;
- resp.cfg.bdpv_min = tic->cfg.bdpv_min;
-
- resp.data.plugged_in = tic->data.is_plugged_in;
- resp.data.standing_by = tic->data.is_standing_by;
- memcpy(resp.data.adco, tic->data.adco, 12);
- resp.data.tarif = tic->data.tarif;
- resp.data.phmode = tic->data.phases;
- resp.data.period = tic->data.period;
- resp.data.isousc = tic->data.isousc;
- resp.data.pa = tic->data.pa;
- resp.data.iinst[0] = tic->data.iinst[0];
- resp.data.iinst[1] = tic->data.iinst[1];
- resp.data.iinst[2] = tic->data.iinst[2];
- resp.data.imax[0] = tic->data.imax[0];
- resp.data.imax[1] = tic->data.imax[1];
- resp.data.imax[2] = tic->data.imax[2];
- resp.data.index_base = tic->data.index_base;
- resp.data.index_hchp_hc = tic->data.index_hchp_hc;
- resp.data.index_hchp_hp = tic->data.index_hchp_hp;
- resp.data.index_tempo_hcjb = tic->data.index_tempo_hcjb;
- resp.data.index_tempo_hpjb = tic->data.index_tempo_hpjb;
- resp.data.index_tempo_hcjw = tic->data.index_tempo_hcjw;
- resp.data.index_tempo_hpjw = tic->data.index_tempo_hpjw;
- resp.data.index_tempo_hcjr = tic->data.index_tempo_hcjr;
- resp.data.index_tempo_hpjr = tic->data.index_tempo_hpjr;
- resp.data.index_ejp_hn = tic->data.index_ejp_hn;
- resp.data.index_ejp_pm = tic->data.index_ejp_pm;
-
- /* Tout va bien, on peut retourner comme quoi on a bien rempli la
- * structure. */
-
- resp.ret = WESPRET_OK;
- set_obj_to_free(wes, tic);
- return (&resp);
-}
+ /* Passer les premiers compteurs. */
+
+ if (args->offset
+ && (ret = (*wes->iface->skipmeters)(iter, args->offset))) {
+ if (wes->iface->delmeteriter)
+ (*wes->iface->delmeteriter)(iter);
+ switch (ret) {
+ default:
+ msg((wlerror, "could not skip meters: %s", error_string(ret)));
+ resp.ret = WESPRET_INT;
+ return (&resp);
+ }
+ }
-/* `get_tic_values_1_svc()`: récupérer des valeurs du compteur via TÉLÉINFO
- * pour une date donnée. */
+ /* Lire les compteurs. */
+
+ while (resp.meters.meters_len < (u_int)args->count) {
+ ret = (*wes->iface->getmeternext)(iter, &meter_id, &meter_type);
+ if (ret == WRITER)
+ break;
+ else if (ret) {
+ if (wes->iface->delmeteriter)
+ (*wes->iface->delmeteriter)(iter);
+
+ resp.meters.meters_len = 0;
+ switch (ret) {
+ default:
+ msg((wlerror, "could not get next meter: %s",
+ error_string(ret)));
+ resp.ret = WESPRET_INT;
+ return (&resp);
+ }
+ }
+
+ /* Traitement dans le tableau. */
+
+ switch (meter_type) {
+ case WESMETERTYPE_NONE:
+ meter_ptype = WESPMETERTYPE_NONE;
+ break;
+ case WESMETERTYPE_AMPER:
+ meter_ptype = WESPMETERTYPE_AMPER;
+ break;
+ case WESMETERTYPE_PULSE:
+ meter_ptype = WESPMETERTYPE_PULSE;
+ break;
+ case WESMETERTYPE_TELEINFO:
+ meter_ptype = WESPMETERTYPE_TELEINFO;
+ break;
+ default:
+ msg((wlerror, "unknown meter type: %d", meter_type));
+
+ if (wes->iface->delmeteriter)
+ (*wes->iface->delmeteriter)(iter);
+
+ resp.ret = WESPRET_INT;
+ resp.meters.meters_len = 0;
+ return (&resp);
+ }
+
+ resp.meters.meters_val[resp.meters.meters_len].id = meter_id;
+ resp.meters.meters_val[resp.meters.meters_len].type = meter_ptype;
+ ++resp.meters.meters_len;
+ }
-wespret_with_ticdata_t *get_tic_values_1_svc(
- wespid_with_tic_id_and_time_t *args, struct svc_req *req)
-{
- static wespret_with_ticdata_t resp;
+ /* Destruction planifiée de l'itérateur. */
- msg((wlnotice, "(%s) get teleinfo %d values on server %d",
- REQADDR, args->tic_id, args->id));
+ if (wes->iface->delmeteriter)
+ (*wes->iface->delmeteriter)(iter);
- resp.ret = WESPRET_IMP;
+ resp.ret = WESPRET_OK;
return (&resp);
}
-/* `set_tic_1_svc()`: Définition de la configuration d'un compteur branché
- * via TÉLÉINFO. */
-
-wespret_t *set_tic_1_svc(wespid_with_tic_t *args, struct svc_req *req)
-{
- static wespret_t ret;
-
- msg((wlnotice, "(%s) set teleinfo %d config on server %d", REQADDR,
- args->tic_id, args->id));
-
- ret = WESPRET_IMP;
- return (&ret);
-}
-
/* ---
* Fonction de lancement du serveur, avec gestions de signaux.
* --- */
@@ -568,7 +838,6 @@ wespret_t *set_tic_1_svc(wespid_with_tic_t *args, struct svc_req *req)
static __attribute__((noreturn)) void its_the_signal(int sig)
{
(void)sig;
-
longjmp(endjmp, 1);
}
@@ -579,7 +848,8 @@ int run_server(weslist_t *llist)
SVCXPRT *tcp = NULL;
/* On stocke les données des appels de service (svc) pour que
- * ceux-ci puissent les utiliser. */
+ * ceux-ci puissent les utiliser. C'est du global parce que l'interface
+ * legacy de SunRPC ne permet pas de transmettre des cookies. */
list = llist;
@@ -607,14 +877,17 @@ int run_server(weslist_t *llist)
/* Lancement de l'application.
* Remarquez la subtilité : on annonce que le serveur tourne alors qu'en
* réalité, pas encore. Mais chut, il ne faut surtout pas que
- * l'administrateur apprenne ça ;) */
+ * l'administrateur apprenne ça, il dirait encore que les développeurs
+ * c'est vraiment que des bidouilleurs ;) */
if (setjmp(endjmp) == 0) {
msg((wlnotice, "The server is now running."));
svc_run();
}
- /* Libération de mémoire. */
+ /* Libération de mémoire.
+ * Malheureusement, il n'y a pas vraiment de moyen de libérer les
+ * ressources allouées en interne par `svc_run()` à ce stade… :/ */
msg((wlnotice, "Stopping the server."));
svc_destroy(tcp);
diff --git a/include/wesh.hpp b/include/wesh.hpp
index 0a16992..9c0ae24 100644
--- a/include/wesh.hpp
+++ b/include/wesh.hpp
@@ -38,7 +38,7 @@
BEGIN_NAMESPACE_WESH
-class electricity_meter;
+class meter_base;
class wes_base;
/* ---
@@ -66,95 +66,232 @@ class NAME: public std::exception { \
} \
};
-WESH_EXC(connexion_exception, "La connexion au démon a échoué.")
-WESH_EXC(daemon_exception, "Le démon a connu une erreur interne.")
+WESH_EXC(connexion_exception,
+ "La connexion au démon a échoué.")
+WESH_EXC(daemon_exception,
+ "Le démon a connu une erreur interne.")
WESH_EXC(not_implemented_exception,
"L'appel correspondant n'est pas implémenté.")
-WESH_EXC(not_loaded_exception, "Cet objet n'a pas été chargé.")
-WESH_EXC(already_created_exception, "Cet objet a déjà été créé !")
+
+WESH_EXC(not_loaded_exception,
+ "Cet objet n'a pas été chargé.")
+WESH_EXC(already_created_exception,
+ "Cet objet a déjà été créé !")
+
WESH_EXC(no_exists_exception,
"Il n'y a pas de serveur WES avec cet identifiant.")
-WESH_EXC(unavailable_exception, "Le serveur WES est injoignable.")
+WESH_EXC(unavailable_exception,
+ "Le serveur WES est injoignable.")
+
+WESH_EXC(no_meter_exception,
+ "Il n'y a pas de compteur avec cet identifiant.")
+WESH_EXC(invalid_meter_type_exception,
+ "Le compteur distant n'est pas du bon type.")
+
+#undef WESH_EXC
/* ---
- * Définition de la classe correspondant à un compteur électrique
- * branché en TÉLÉINFO.
+ * Énumérations utiles pour ce qui concerne les compteurs.
* --- */
-enum electricity_meter_mode {
- emm_conso = 0, /* Consommation */
- emm_prod = 1 /* Production */
+/* Mode de consommation/production d'un compteur.
+ * `conso`: consommation.
+ * `prod`: production (panneaux solaires, …). */
+
+enum meter_mode {
+ mm_conso,
+ mm_prod
};
-enum electricity_meter_subscription_type {
- emst_base = 0, /* BASE (toutes heures) */
- emst_hchp = 1, /* Heures Creuses, Heures Pleines */
- emst_ejp = 2, /* Effacement de Jours de Pointes */
- emst_tempo = 3 /* Temporaires (jours bleus, blancs, rouges + hchp) */
+/* Grandeur mesurée par le compteur.
+ * `water`: eau froide/chaude.
+ * `gas`: gaz.
+ * `electricity`: electricité.
+ * `fuel`: fioul. */
+
+enum meter_what {
+ mw_water,
+ mw_gas,
+ mw_elec,
+ mw_fuel
};
-enum electricity_meter_subscription_period {
- emsp_hn = 0, /* Heures Normales/Toutes les Heures */
- emsp_hc = 1, /* Heures Creuses (HCHP) */
- emsp_hp = 2, /* Heures Pleines (HCHP) */
- emsp_pm = 3, /* Heures de Pointe Mobile (EJP) */
-
- emsp_hcjb = 1, /* Heures Creuses Jours Bleus */
- emsp_hpjb = 2, /* Heures Pleines Jours Bleus */
- emsp_hcjw = 5, /* Heures Creuses Jours Blancs */
- emsp_hpjw = 6, /* Heures Pleines Jours Blancs */
- emsp_hcjr = 9, /* Heures Creuses Jours Rouges */
- emsp_hpjr = 10 /* Heures Pleines Jours Rouges */
+/* Unité des valeurs pour la grandeur mesurée par le compteur.
+ * `wh`: watts par heure (Wh).
+ * `kwh`: kilo-watts par heure (kWh).
+ * `liter`: litres (L).
+ * `cubicmeter`: mètres cube (m³). */
+
+enum meter_unit {
+ mu_wh,
+ mu_kwh,
+ mu_liter,
+ mu_cubicmeter
};
-struct electricity_meter_subscription {
- electricity_meter_subscription_type type;
- electricity_meter_subscription_period period;
+/* Type de tarif pour le protocole télé-informatique d'ERDF.
+ * `base`: forfait Base (toutes heures), le prix du kWh ne varie pas en
+ * fonction de la période de consommation ;
+ * `hchp`: forfait Heures Pleines Heures Creuses, le prix du kWh varie
+ * en fonction de l'heure de la journée ;
+ * `tempo`: forfait Temporaire, le prix du kWh varie en fonction de l'heure
+ * de la journée, ainsi que de la couleur de la journée ;
+ * `ejp`: forfait Effacement de Jour de Pointe, le prix du kWh varie en
+ * fonction de la journée. */
+
+enum teleinfo_meter_subscription_type {
+ ticmst_base,
+ ticmst_hchp,
+ ticmst_ejp,
+ ticmst_tempo
};
-enum electricity_meter_phase_mode {
- empm_none = 0, /* aucune phase */
- empm_mono = 1, /* monophasé */
- empm_tri = 3 /* triphasé */
+/* Période tarifaire pour le protocole télé-informatique d'ERDF.
+ * La signification des valeurs dans cette énumération dépend du forfait
+ * souscrit pour ce compteur.
+ *
+ * Forfait BASE :
+ * `th`: toutes heures.
+ *
+ * Forfait HCHP :
+ * `hc`: heures creuses.
+ * `hp`: heures pleines.
+ *
+ * Forfait TEMPO :
+ * `hcjb`: heures creuses en jours bleus.
+ * `hpjb`: heures pleines en jours bleus.
+ * `hcjw`: heures creuses en jours blancs.
+ * `hpjw`: heures pleines en jours blancs.
+ * `hcjr`: heures creuses en jours rouges.
+ * `hpjr`: heures pleines en jours rouges.
+ *
+ * Forfait EJP :
+ * `hn`: heures normales.
+ * `pm`: pointes mobiles. */
+
+enum teleinfo_meter_subscription_period {
+ ticmsp_th = 0,
+ ticmsp_hn = 0,
+ ticmsp_hc = 1,
+ ticmsp_hp = 2,
+ ticmsp_pm = 3,
+
+ ticmsp_hcjb = 1,
+ ticmsp_hpjb = 2,
+ ticmsp_hcjw = 5,
+ ticmsp_hpjw = 6,
+ ticmsp_hcjr = 9,
+ ticmsp_hpjr = 10
+};
+
+/* Structure concernant le forfait actuel d'un compteur électrique
+ * branché via télé-information. */
+
+struct teleinfo_meter_subscription {
+ teleinfo_meter_subscription_type type;
+ teleinfo_meter_subscription_period period;
+};
+
+/* Méthodes d'impulsions pour un compteur d'impulsions.
+ * `ils`: impulsions mécaniques.
+ * `elec`: impulsions électroniques. */
+
+enum pulse_meter_method {
+ pmm_ils,
+ pmm_elec
};
-class electricity_meter {
+# ifndef WESH_CLIENT_TYPE
+# define WESH_CLIENT_TYPE void
+# endif
+
+/* ---
+ * Classes concernant un compteur.
+ * --- */
+
+class meter_base {
private:
wes_base *parent;
- int num;
+ int id;
public:
- electricity_meter(void);
- electricity_meter(wes_base *parent, int num);
+ meter_base(void);
+ meter_base(wes_base *parent, int num);
+
+ /* Récupération des données concernant le compteur. */
void gather(wes_base *parent, int num);
void gather(void);
- void update(void);
+ /* Récupération de données depuis le démon. */
- /* Configuration. */
+ std::string get_name(void);
+ void set_name(std::string name);
- bool is_read;
- std::string name;
- electricity_meter_mode mode;
+ bool enabled(void);
+ void enable(void);
+ void disable(void);
- /* Données. */
+ meter_mode get_mode(void);
+ void set_mode(meter_mode mode);
- electricity_meter_subscription subscription;
- electricity_meter_phase_mode phase_mode;
+ meter_what get_what(void);
+ void set_what(meter_what what);
+
+ double get_fixed_costs(void);
+ void set_fixed_costs(double cost);
+};
+
+class clamp: public meter_base {
+public:
+ clamp(void) : meter_base() {}
+ clamp(wes_base *parent, int num) : meter_base(parent, num) {}
+
+ int get_voltage(void);
+ void set_voltage(int voltage);
+
+ double get_unit_cost(void);
+ void set_unit_cost(double cost);
+};
+
+class pulse_meter: public meter_base {
+public:
+ pulse_meter(void) : meter_base() {}
+ pulse_meter(wes_base *parent, int num) : meter_base(parent, num) {}
+
+ pulse_meter_method get_method(void);
+ void set_method(pulse_meter_method method);
+
+ int get_pulses_per_unit(void);
+ void set_pulses_per_unit(int number);
+
+ double get_unit_cost(void);
+ void set_unit_cost(double cost);
+};
+
+class teleinfo_meter: public meter_base {
+public:
+ teleinfo_meter(void) : meter_base() {}
+ teleinfo_meter(wes_base *parent, int num) : meter_base(parent, num) {}
+
+ double get_unit_cost(teleinfo_meter_subscription sub);
+ void set_unit_cost(teleinfo_meter_subscription sub, double cost);
+
+ bool bdpv_enabled(void);
+ void enable_bdpv(void);
+ void disable_bdpv(void);
+
+ std::pair<int, int> is_sent_to_bdpv_at(void);
+ void send_to_bdpv_at(int hour, int min);
+
+ std::pair<std::string, std::string> get_bdpv_ids(void);
+ void set_bdpv_ids(std::string username, std::string password);
};
/* ---
* Définition des classes WES.
* --- */
-# ifndef WESH_CLIENT_TYPE
-# define WESH_CLIENT_TYPE void
-# endif
-# ifndef WESH_GATHER_TYPE
-# define WESH_GATHER_TYPE void
-# endif
-
/* Classe de base, pour toutes les interfaces derrière. */
class wes_base {
@@ -162,10 +299,6 @@ protected:
int id;
WESH_CLIENT_TYPE *client;
- /* Récupération de la ressource, version privée. */
-
- void gather_(WESH_GATHER_TYPE *args);
-
public:
wes_base(void);
virtual ~wes_base(void);
@@ -182,10 +315,15 @@ public:
void set_name(std::string name);
void set_name(const char *name);
- /* Récupérer l'heure. */
+ /* Gestion de l'heure. */
struct tm get_date(void);
- electricity_meter get_electricity_meter(int id);
+
+ /* Récupération de compteurs. */
+
+ clamp get_clamp(int id);
+ pulse_meter get_pulse_meter(int id);
+ teleinfo_meter get_teleinfo_meter(int id);
/* Destiné aux classes ayant ce serveur comme référent. */
@@ -247,15 +385,20 @@ END_NAMESPACE_WESH
extern std::ostream& operator<<(std::ostream& os,
wesh::wes_base& wes);
+
+extern std::ostream& operator<<(std::ostream& os,
+ wesh::meter_mode md);
+extern std::ostream& operator<<(std::ostream& os,
+ wesh::meter_what wh);
extern std::ostream& operator<<(std::ostream& os,
- wesh::electricity_meter_mode md);
+ wesh::meter_unit un);
extern std::ostream& operator<<(std::ostream& os,
- wesh::electricity_meter_subscription_type st);
+ wesh::teleinfo_meter_subscription_type st);
extern std::ostream& operator<<(std::ostream& os,
- wesh::electricity_meter_subscription sb);
+ wesh::teleinfo_meter_subscription_period pd);
extern std::ostream& operator<<(std::ostream& os,
- wesh::electricity_meter_subscription_period pd);
+ wesh::teleinfo_meter_subscription sb);
extern std::ostream& operator<<(std::ostream& os,
- wesh::electricity_meter_phase_mode pm);
+ wesh::pulse_meter_method pl);
#endif /* WESH_HPP */
diff --git a/lib/electricity_meter.cpp b/lib/electricity_meter.cpp
deleted file mode 100644
index 01f5b76..0000000
--- a/lib/electricity_meter.cpp
+++ /dev/null
@@ -1,346 +0,0 @@
-/* ****************************************************************************
- * electricity_meter.cpp -- méthodes de la classe `electricity_meter`.
- * Copyright (C) 2018 Thomas Touhey <thomas@touhey.fr>
- *
- * This project is governed by the CeCILL license under French law and
- * abiding by the rules of distribution of free software. You can use,
- * modify and/or redistribute the software under the terms of the
- * CeCILL license as circulated by CEA, CNRS and INRIA at the
- * following URL: "http://www.cecill.info".
- *
- * As a counterpart to the access to the source code and rights to copy,
- * modify and redistribute granted by the license, users are provided only
- * with a limited warranty and the project's author, the holder of the
- * economic rights, and the successive licensors have only limited liability.
- *
- * In this respect, the user's attention is drawn to the risks associated
- * with loading, using, modifying and/or developing or reproducing the
- * software by the user in light of its specific status of free software,
- * that may mean that it is complicated to manipulate, and that also therefore
- * means that it is reserved for developers and experienced professionals
- * having in-depth computer knowledge. Users are therefore encouraged to load
- * and test the software's suitability as regards their requirements in
- * conditions enabling the security of their systems and/or data to be
- * ensured and, more generally, to use and operate it in the same conditions
- * as regards security.
- *
- * The fact that you are presently reading this means that you have had
- * knowledge of the CeCILL license and that you accept its terms.
- * ************************************************************************* */
-#include "internals.hpp"
-
-using namespace wesh;
-
-/* ---
- * Affichages des énumérations.
- * --- */
-
-std::ostream& operator<<(std::ostream& os,
- electricity_meter_mode md)
-{
- switch (md) {
- case emm_conso:
- os << "CONSO";
- break;
- case emm_prod:
- os << "PROD";
- break;
- default:
- os << "(unknown)";
- break;
- }
-
- return (os);
-}
-
-std::ostream& operator<<(std::ostream& os,
- electricity_meter_subscription_type st)
-{
- switch (st) {
- case emst_base:
- os << "BASE";
- break;
- case emst_hchp:
- os << "HCHP";
- break;
- case emst_ejp:
- os << "EJP";
- break;
- case emst_tempo:
- os << "TEMPO";
- break;
- default:
- os << "(unknown)";
- break;
- }
-
- return (os);
-}
-
-std::ostream& operator<<(std::ostream& os,
- electricity_meter_subscription_period pd)
-{
- switch (pd) {
- case emsp_hn:
- os << "HN/TH";
- break;
- case emsp_hc:
- os << "HC(JB)";
- break;
- case emsp_hp:
- os << "HP(JB)";
- break;
- case emsp_pm:
- os << "PM";
- break;
- case emsp_hcjw:
- os << "HCJW";
- break;
- case emsp_hpjw:
- os << "HPJW";
- break;
- case emsp_hcjr:
- os << "HCJR";
- break;
- case emsp_hpjr:
- os << "HPJR";
- break;
- default:
- os << "(unknown)";
- break;
- }
-
- return (os);
-}
-
-std::ostream& operator<<(std::ostream& os,
- wesh::electricity_meter_subscription sb)
-{
- switch (sb.type) {
- case emst_base: switch (sb.period) {
- case emsp_hn:
- os << "BASE";
- break;
- default:
- os << "(unknown)";
- } break;
- case emst_hchp: switch (sb.period) {
- case emsp_hc:
- os << "HCHC";
- break;
- case emsp_hp:
- os << "HCHP";
- break;
- default:
- os << "(unknown)";
- } break;
- case emst_ejp: switch (sb.period) {
- case emsp_hn:
- os << "EJPHN";
- break;
- case emsp_pm:
- os << "EJPPM";
- break;
- default:
- os << "(unknown)";
- } break;
- case emst_tempo: switch (sb.period) {
- case emsp_hcjb:
- os << "HCJB";
- break;
- case emsp_hpjb:
- os << "HPJB";
- break;
- case emsp_hcjw:
- os << "HCJW";
- break;
- case emsp_hpjw:
- os << "HPJW";
- break;
- case emsp_hcjr:
- os << "HCJR";
- break;
- case emsp_hpjr:
- os << "HPJR";
- break;
- default:
- os << "(unknown)";
- } break;
- default:
- os << "(unknown)";
- }
-
- return (os);
-}
-
-std::ostream& operator<<(std::ostream& os,
- electricity_meter_phase_mode pm)
-{
- switch (pm) {
- case empm_none:
- os << "(none)";
- break;
- case empm_mono:
- os << "MONO";
- break;
- case empm_tri:
- os << "TRI";
- break;
- default:
- os << "(unknown)";
- break;
- }
-
- return (os);
-}
-
-/* ---
- * Constructeur, destructeur.
- * --- */
-
-electricity_meter::electricity_meter(void)
-{
- this->parent = nullptr;
- this->num = -1;
-}
-
-electricity_meter::electricity_meter(wes_base *parent_to_use, int num_to_use)
-{
- /* FIXME: Vérifier si les arguments sont valides. */
-
- this->parent = parent_to_use;
- this->num = num_to_use;
-
- this->gather();
-}
-
-/* ---
- * Récupération de l'objet.
- * --- */
-
-/* Remarque : l'absence de `default` dans les switch est volontaire. */
-
-void electricity_meter::gather(void)
-{
- wespid_with_tic_id_t args = {
- static_cast<wespid_t>(this->parent->get_id()),
- this->num};
- wespret_with_tic_t *resp;
-
- if (this->num < 0)
- throw not_loaded_exception();
-
- /* Requête au démon. */
-
- resp = get_tic_1(&args, clnt(this->parent));
- if (!resp)
- throw connexion_exception();
-
- if (resp->ret != WESPRET_OK)
- throw_exception_using_ret(resp->ret);
-
- this->is_read = resp->cfg.read;
- this->name = std::string(resp->cfg.name);
-
- switch (resp->cfg.mode) {
- case WESPTICMODE_CONSO:
- this->mode = emm_conso;
- break;
- case WESPTICMODE_PROD:
- this->mode = emm_prod;
- break;
- default:
- throw daemon_exception();
- }
-
- switch (resp->data.tarif) {
- case WESPTICTARIF_BASE:
- this->subscription.type = emst_base;
- this->subscription.period = emsp_hn;
- break;
- case WESPTICTARIF_HCHP:
- this->subscription.type = emst_hchp;
- switch (resp->data.period & ~(WESPTICPERIOD_JB | WESPTICPERIOD_JR)) {
- case WESPTICPERIOD_HC:
- this->subscription.period = emsp_hc;
- break;
- case WESPTICPERIOD_HP:
- this->subscription.period = emsp_hp;
- break;
- default:
- throw daemon_exception();
- }
- break;
- case WESPTICTARIF_EJP:
- this->subscription.type = emst_ejp;
- switch (resp->data.period) {
- case WESPTICPERIOD_HN:
- this->subscription.period = emsp_hn;
- break;
- case WESPTICPERIOD_PM:
- this->subscription.period = emsp_pm;
- break;
- default:
- throw daemon_exception();
- }
- break;
- case WESPTICTARIF_TEMPO:
- this->subscription.type = emst_tempo;
- switch (resp->data.period) {
- case WESPTICPERIOD_HCJB:
- this->subscription.period = emsp_hcjb;
- break;
- case WESPTICPERIOD_HPJB:
- this->subscription.period = emsp_hpjb;
- break;
- case WESPTICPERIOD_HCJW:
- this->subscription.period = emsp_hcjw;
- break;
- case WESPTICPERIOD_HPJW:
- this->subscription.period = emsp_hpjw;
- break;
- case WESPTICPERIOD_HCJR:
- this->subscription.period = emsp_hcjr;
- break;
- case WESPTICPERIOD_HPJR:
- this->subscription.period = emsp_hpjr;
- break;
- default:
- throw daemon_exception();
- }
- break;
- default:
- throw daemon_exception();
- }
-
- switch (resp->data.phmode) {
- case WESPTICPHMODE_NONE:
- this->phase_mode = empm_none;
- break;
- case WESPTICPHMODE_MONO:
- this->phase_mode = empm_mono;
- break;
- case WESPTICPHMODE_TRI:
- this->phase_mode = empm_tri;
- break;
- default:
- throw daemon_exception();
- }
-
- /* TODO: other values */
-}
-
-void electricity_meter::gather(wes_base *parent_now, int num_now)
-{
- if (this->num >= 0)
- throw not_loaded_exception();
-
- /* FIXME: vérifier si les arguments sont valides. */
-
- this->parent = parent_now;
- this->num = num_now;
-
- this->gather();
-}
-
-/* TODO: electricity_meter::update() */
diff --git a/lib/helpers.cpp b/lib/helpers.cpp
index 3445e46..a47a105 100644
--- a/lib/helpers.cpp
+++ b/lib/helpers.cpp
@@ -31,6 +31,224 @@
using namespace wesh;
+/* ---
+ * Utilitaires d'affichage (mise sur un flux de sortie).
+ * --- */
+
+std::ostream& operator<<(std::ostream& os, wes_base& wes)
+{
+ os << "<wes"
+ << " name=\"" << wes.get_name() << "\""
+ << " iface=\"" << wes.iface() << "\""
+ << ">";
+
+ return (os);
+}
+
+std::ostream& operator<<(std::ostream& os, meter_mode md)
+{
+ switch (md) {
+ case mm_conso:
+ os << "CONSO";
+ break;
+ case mm_prod:
+ os << "PROD";
+ break;
+ default:
+ os << "(unknown)";
+ break;
+ }
+
+ return (os);
+}
+
+std::ostream& operator<<(std::ostream& os, meter_what wh)
+{
+ switch (wh) {
+ case mw_water:
+ os << "Eau";
+ break;
+ case mw_gas:
+ os << "Gaz";
+ break;
+ case mw_elec:
+ os << "Électricité";
+ break;
+ case mw_fuel:
+ os << "Fioul";
+ break;
+ default:
+ os << "(unknown)";
+ break;
+ }
+
+ return (os);
+}
+
+std::ostream& operator<<(std::ostream& os, meter_unit un)
+{
+ switch (un) {
+ case mu_wh:
+ os << "Wh";
+ break;
+ case mu_kwh:
+ os << "kWh";
+ break;
+ case mu_liter:
+ os << "L";
+ break;
+ case mu_cubicmeter:
+ os << "m³";
+ break;
+ default:
+ os << "(unknown)";
+ break;
+ }
+
+ return (os);
+}
+
+std::ostream& operator<<(std::ostream& os,
+ teleinfo_meter_subscription_type st)
+{
+ switch (st) {
+ case ticmst_base:
+ os << "BASE";
+ break;
+ case ticmst_hchp:
+ os << "HCHP";
+ break;
+ case ticmst_ejp:
+ os << "EJP";
+ break;
+ case ticmst_tempo:
+ os << "TEMPO";
+ break;
+ default:
+ os << "(unknown)";
+ break;
+ }
+
+ return (os);
+}
+
+std::ostream& operator<<(std::ostream& os,
+ teleinfo_meter_subscription_period pd)
+{
+ switch (pd) {
+ case ticmsp_hn:
+ os << "HN/TH";
+ break;
+ case ticmsp_hc:
+ os << "HC(JB)";
+ break;
+ case ticmsp_hp:
+ os << "HP(JB)";
+ break;
+ case ticmsp_pm:
+ os << "PM";
+ break;
+ case ticmsp_hcjw:
+ os << "HCJW";
+ break;
+ case ticmsp_hpjw:
+ os << "HPJW";
+ break;
+ case ticmsp_hcjr:
+ os << "HCJR";
+ break;
+ case ticmsp_hpjr:
+ os << "HPJR";
+ break;
+ default:
+ os << "(unknown)";
+ break;
+ }
+
+ return (os);
+}
+
+std::ostream& operator<<(std::ostream& os,
+ teleinfo_meter_subscription sb)
+{
+ switch (sb.type) {
+ case ticmst_base: switch (sb.period) {
+ case ticmsp_hn:
+ os << "BASE";
+ break;
+ default:
+ os << "(unknown)";
+ } break;
+ case ticmst_hchp: switch (sb.period) {
+ case ticmsp_hc:
+ os << "HCHC";
+ break;
+ case ticmsp_hp:
+ os << "HCHP";
+ break;
+ default:
+ os << "(unknown)";
+ } break;
+ case ticmst_ejp: switch (sb.period) {
+ case ticmsp_hn:
+ os << "EJPHN";
+ break;
+ case ticmsp_pm:
+ os << "EJPPM";
+ break;
+ default:
+ os << "(unknown)";
+ } break;
+ case ticmst_tempo: switch (sb.period) {
+ case ticmsp_hcjb:
+ os << "HCJB";
+ break;
+ case ticmsp_hpjb:
+ os << "HPJB";
+ break;
+ case ticmsp_hcjw:
+ os << "HCJW";
+ break;
+ case ticmsp_hpjw:
+ os << "HPJW";
+ break;
+ case ticmsp_hcjr:
+ os << "HCJR";
+ break;
+ case ticmsp_hpjr:
+ os << "HPJR";
+ break;
+ default:
+ os << "(unknown)";
+ } break;
+ default:
+ os << "(unknown)";
+ }
+
+ return (os);
+}
+
+std::ostream& operator<<(std::ostream& os, pulse_meter_method pl)
+{
+ switch (pl) {
+ case pmm_ils:
+ os << "ILS (mécanique)";
+ break;
+ case pmm_elec:
+ os << "Électronique";
+ break;
+ default:
+ os << "(unknown)";
+ break;
+ }
+
+ return (os);
+}
+
+/* ---
+ * Utilitaires concernant les exceptions.
+ * --- */
+
/* `throw_exception_using_ret()`: utilisation du code de retour pour savoir
* quelle exception soulever. */
diff --git a/lib/internals.hpp b/lib/internals.hpp
index fb6b572..f610582 100644
--- a/lib/internals.hpp
+++ b/lib/internals.hpp
@@ -35,7 +35,6 @@
extern "C" {
# include <weshd.h>
-# undef gather
}
/* Inclusion du header public, en redéfinissant ce qu'il faut. */
diff --git a/lib/meter/clamp.cpp b/lib/meter/clamp.cpp
new file mode 100644
index 0000000..54ceed5
--- /dev/null
+++ b/lib/meter/clamp.cpp
@@ -0,0 +1,34 @@
+/* ****************************************************************************
+ * meter/clamp.cpp -- méthodes de la classe `clamp`.
+ * Copyright (C) 2018 Thomas Touhey <thomas@touhey.fr>
+ *
+ * This project is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/or redistribute the software under the terms of the
+ * CeCILL license as circulated by CEA, CNRS and INRIA at the
+ * following URL: "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the project's author, the holder of the
+ * economic rights, and the successive licensors have only limited liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also therefore
+ * means that it is reserved for developers and experienced professionals
+ * having in-depth computer knowledge. Users are therefore encouraged to load
+ * and test the software's suitability as regards their requirements in
+ * conditions enabling the security of their systems and/or data to be
+ * ensured and, more generally, to use and operate it in the same conditions
+ * as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ * ************************************************************************* */
+#include "../internals.hpp"
+
+using namespace wesh;
+
+/* TODO */
diff --git a/lib/meter/meter_base.cpp b/lib/meter/meter_base.cpp
new file mode 100644
index 0000000..14a08cf
--- /dev/null
+++ b/lib/meter/meter_base.cpp
@@ -0,0 +1,95 @@
+/* ****************************************************************************
+ * meter/meter_base.cpp -- méthodes de la classe `meter_base`.
+ * Copyright (C) 2018 Thomas Touhey <thomas@touhey.fr>
+ *
+ * This project is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/or redistribute the software under the terms of the
+ * CeCILL license as circulated by CEA, CNRS and INRIA at the
+ * following URL: "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the project's author, the holder of the
+ * economic rights, and the successive licensors have only limited liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also therefore
+ * means that it is reserved for developers and experienced professionals
+ * having in-depth computer knowledge. Users are therefore encouraged to load
+ * and test the software's suitability as regards their requirements in
+ * conditions enabling the security of their systems and/or data to be
+ * ensured and, more generally, to use and operate it in the same conditions
+ * as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ * ************************************************************************* */
+#include "../internals.hpp"
+
+using namespace wesh;
+
+/* ---
+ * Constructeur, destructeur.
+ * --- */
+
+meter_base::meter_base(void)
+{
+ this->parent = nullptr;
+ this->id = -1;
+}
+
+meter_base::meter_base(wes_base *parent_to_use, int num_to_use)
+{
+ if (!parent_to_use || num_to_use <= 0 || num_to_use > 32766)
+ throw no_meter_exception();
+
+ /* FIXME: Vérifier si les arguments sont valides. */
+
+ this->parent = parent_to_use;
+ this->id = num_to_use;
+
+ this->gather();
+}
+
+/* ---
+ * Récupération de l'objet.
+ * --- */
+
+/* Remarque : l'absence de `default` dans les switch est volontaire. */
+
+void meter_base::gather(void)
+{
+ wespid_with_meter_id_t args = {
+ static_cast<wespid_t>(this->parent->get_id()),
+ this->num};
+ wespret_with_tic_t *resp;
+
+ if (this->num < 0)
+ throw not_loaded_exception();
+
+ /* Requête au démon. */
+
+ resp = get_tic_1(&args, clnt(this->parent));
+ if (!resp)
+ throw connexion_exception();
+
+ /* TODO: other values */
+}
+
+void meter_base::gather(wes_base *parent_now, int num_now)
+{
+ if (this->num >= 0)
+ throw not_loaded_exception();
+
+ /* FIXME: vérifier si les arguments sont valides. */
+
+ this->parent = parent_now;
+ this->num = num_now;
+
+ this->gather();
+}
+
+/* TODO: meter_base::update() */
diff --git a/lib/meter/pulse_meter.cpp b/lib/meter/pulse_meter.cpp
new file mode 100644
index 0000000..bb988dd
--- /dev/null
+++ b/lib/meter/pulse_meter.cpp
@@ -0,0 +1,34 @@
+/* ****************************************************************************
+ * meter/pulse_meter.cpp -- méthodes de la classe `pulse_meter`.
+ * Copyright (C) 2018 Thomas Touhey <thomas@touhey.fr>
+ *
+ * This project is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/or redistribute the software under the terms of the
+ * CeCILL license as circulated by CEA, CNRS and INRIA at the
+ * following URL: "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the project's author, the holder of the
+ * economic rights, and the successive licensors have only limited liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also therefore
+ * means that it is reserved for developers and experienced professionals
+ * having in-depth computer knowledge. Users are therefore encouraged to load
+ * and test the software's suitability as regards their requirements in
+ * conditions enabling the security of their systems and/or data to be
+ * ensured and, more generally, to use and operate it in the same conditions
+ * as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ * ************************************************************************* */
+#include "../internals.hpp"
+
+using namespace wesh;
+
+/* TODO */
diff --git a/lib/meter/teleinfo_meter.cpp b/lib/meter/teleinfo_meter.cpp
new file mode 100644
index 0000000..1f8d800
--- /dev/null
+++ b/lib/meter/teleinfo_meter.cpp
@@ -0,0 +1,34 @@
+/* ****************************************************************************
+ * meter/teleinfo_meter.cpp -- méthodes de la classe `teleinfo_meter`.
+ * Copyright (C) 2018 Thomas Touhey <thomas@touhey.fr>
+ *
+ * This project is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/or redistribute the software under the terms of the
+ * CeCILL license as circulated by CEA, CNRS and INRIA at the
+ * following URL: "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the project's author, the holder of the
+ * economic rights, and the successive licensors have only limited liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also therefore
+ * means that it is reserved for developers and experienced professionals
+ * having in-depth computer knowledge. Users are therefore encouraged to load
+ * and test the software's suitability as regards their requirements in
+ * conditions enabling the security of their systems and/or data to be
+ * ensured and, more generally, to use and operate it in the same conditions
+ * as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ * ************************************************************************* */
+#include "../internals.hpp"
+
+using namespace wesh;
+
+/* TODO */
diff --git a/lib/dummy_wes.cpp b/lib/wes/dummy_wes.cpp
index 9458ecc..6b36c4c 100644
--- a/lib/dummy_wes.cpp
+++ b/lib/wes/dummy_wes.cpp
@@ -1,5 +1,5 @@
/* ****************************************************************************
- * dummy_wes.cpp -- méthodes de la classe `dummy_wes`.
+ * wes/dummy_wes.cpp -- classe `dummy_wes` héritée de `wes_base`.
* Copyright (C) 2018 Thomas Touhey <thomas@touhey.fr>
*
* This project is governed by the CeCILL license under French law and
@@ -27,26 +27,32 @@
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL license and that you accept its terms.
* ************************************************************************* */
-#include "internals.hpp"
+#include "../internals.hpp"
using namespace wesh;
-static char empty[1] = "";
-
/* ---
* Récupération de la ressource.
* --- */
void dummy_wes::gather(void)
{
- wespregopts_t args;
+ wespoptions_t args;
+ wespret_with_id_t *resp;
+ wespret_t ret;
+
+ if (this->id != 0)
+ throw already_created_exception();
+
+ args.type = WESPTYPE_DUMMY;
+
+ resp = gather_1(&args, clnt(this));
+ if (!resp)
+ throw connexion_exception();
- args.type = WESPREGTYPE_DUMMY;
- args.ip.type = WESPIPTYPE_NONE;
- args.http_username = empty;
- args.http_password = empty;
- args.ftp_username = empty;
- args.ftp_password = empty;
+ ret = resp->ret;
+ if (ret != WESPRET_OK)
+ throw_exception_using_ret(ret);
- this->gather_(&args);
+ this->id = resp->id;
}
diff --git a/lib/wes.cpp b/lib/wes/wes.cpp
index ead741a..b8d469d 100644
--- a/lib/wes.cpp
+++ b/lib/wes/wes.cpp
@@ -1,5 +1,5 @@
/* ****************************************************************************
- * wes.cpp -- méthodes de la classe `wes`.
+ * wes/wes.cpp -- méthodes de la classe `wes` héritée de `wes_base`.
* Copyright (C) 2018 Thomas Touhey <thomas@touhey.fr>
*
* This project is governed by the CeCILL license under French law and
@@ -27,7 +27,7 @@
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL license and that you accept its terms.
* ************************************************************************* */
-#include "internals.hpp"
+#include "../internals.hpp"
using namespace wesh;
@@ -78,29 +78,42 @@ void wes::gather(const unsigned char ip[4],
std::string http_username, std::string http_password,
std::string ftp_username, std::string ftp_password)
{
- wespregopts_t args;
+ wespoptions_t args;
+ wespret_with_id_t *resp;
+ wespret_t ret;
char hu[http_username.length() + 1],
hp[http_password.length() + 1],
fu[ftp_username.length() + 1],
fp[ftp_password.length() + 1];
+ if (this->id != 0)
+ throw already_created_exception();
+
strcpy(hu, http_username.c_str());
strcpy(hp, http_password.c_str());
strcpy(fu, ftp_username.c_str());
strcpy(fp, ftp_password.c_str());
- args.type = WESPREGTYPE_IP;
- args.ip.type = WESPIPTYPE_4;
- args.ip.ipv4[0] = ip[0];
- args.ip.ipv4[1] = ip[1];
- args.ip.ipv4[2] = ip[2];
- args.ip.ipv4[3] = ip[3];
- args.http_username = hu;
- args.http_password = hp;
- args.ftp_username = fu;
- args.ftp_password = fp;
-
- this->gather_(&args);
+ args.type = WESPTYPE_IP;
+ args.wespoptions_t_u.ip.addr.type = WESPIPTYPE_4;
+ args.wespoptions_t_u.ip.addr.wespip_t_u.addr4[0] = ip[0];
+ args.wespoptions_t_u.ip.addr.wespip_t_u.addr4[1] = ip[1];
+ args.wespoptions_t_u.ip.addr.wespip_t_u.addr4[2] = ip[2];
+ args.wespoptions_t_u.ip.addr.wespip_t_u.addr4[3] = ip[3];
+ args.wespoptions_t_u.ip.http_username = hu;
+ args.wespoptions_t_u.ip.http_password = hp;
+ args.wespoptions_t_u.ip.ftp_username = fu;
+ args.wespoptions_t_u.ip.ftp_password = fp;
+
+ resp = gather_1(&args, clnt(this));
+ if (!resp)
+ throw connexion_exception();
+
+ ret = resp->ret;
+ if (ret != WESPRET_OK)
+ throw_exception_using_ret(ret);
+
+ this->id = resp->id;
}
void wes::gather(const std::string ip,
diff --git a/lib/wes_base.cpp b/lib/wes/wes_base.cpp
index be5551d..6f75b6c 100644
--- a/lib/wes_base.cpp
+++ b/lib/wes/wes_base.cpp
@@ -1,5 +1,5 @@
/* ****************************************************************************
- * wes_base.cpp -- méthodes de la classe `wes_base`.
+ * wes/wes_base.cpp -- méthodes de la classe `wes_base`.
* Copyright (C) 2018 Thomas Touhey <thomas@touhey.fr>
*
* This project is governed by the CeCILL license under French law and
@@ -27,22 +27,11 @@
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL license and that you accept its terms.
* ************************************************************************* */
-#include "internals.hpp"
+#include "../internals.hpp"
using namespace wesh;
/* ---
- * Affichages divers.
- * --- */
-
-std::ostream& operator<<(std::ostream& os, wes_base& wes)
-{
- os << "<wes name=" << wes.get_name() << " iface=" << wes.iface() << ">";
-
- return (os);
-}
-
-/* ---
* Constructeur, destructeur.
* --- */
@@ -84,25 +73,6 @@ int wes_base::get_id(void)
* Récupération et suppression de la ressource.
* --- */
-void wes_base::gather_(wespregopts_t *args)
-{
- wespret_with_id_t *resp;
- wespret_t ret;
-
- if (this->id != 0)
- throw already_created_exception();
-
- resp = gather_1(args, clnt(this));
- if (!resp)
- throw connexion_exception();
-
- ret = resp->ret;
- if (ret != WESPRET_OK)
- throw_exception_using_ret(ret);
-
- this->id = resp->id;
-}
-
void wes_base::use(int given_id)
{
if (this->id != 0)
@@ -137,21 +107,22 @@ void wes_base::remove(void)
std::string wes_base::get_name(void)
{
- wespid_t wid;
- wespret_with_hostname_t *resp;
+ wespid_with_wes_flags_t args;
+ wespret_with_wes_t *resp;
if (this->id == 0)
throw not_loaded_exception();
- wid = static_cast<wespid_t>(this->id);
- resp = get_host_name_1(&wid, clnt(this));
+ args.id = static_cast<wespid_t>(this->id);
+ args.to_get = WESP_NAME;
+ resp = get_1(&args, clnt(this));
if (!resp)
throw connexion_exception();
if (resp->ret != WESPRET_OK)
throw_exception_using_ret(resp->ret);
- return (std::string(resp->hostname));
+ return (std::string(resp->wes.name));
}
void wes_base::set_name(std::string name_to_set)
@@ -161,7 +132,7 @@ void wes_base::set_name(std::string name_to_set)
void wes_base::set_name(const char *name_to_set)
{
- wespid_with_hostname_t args;
+ wespid_with_wes_t args;
wespret_t ret, *retp;
if (this->id == 0)
@@ -178,9 +149,10 @@ void wes_base::set_name(const char *name_to_set)
namebuf[len] = '\0';
args.id = static_cast<wespid_t>(this->id);
- args.hostname = namebuf;
+ args.wes.name = namebuf;
+ args.wes.to_set = WESP_NAME;
- retp = set_host_name_1(&args, clnt(this));
+ retp = set_1(&args, clnt(this));
if (!retp)
throw connexion_exception();
}
@@ -191,28 +163,29 @@ void wes_base::set_name(const char *name_to_set)
}
/* ---
- * Récupération d'éléments.
+ * Récupération de la date.
* --- */
struct tm wes_base::get_date(void)
{
- wespid_t wid;
- wespret_with_datetime_t *resp;
- wespdatetime_t *dt;
+ wespid_with_wes_flags_t args;
+ wespret_with_wes_t *resp;
+ wespdt_t *dt;
struct tm tm;
if (this->id == 0)
throw not_loaded_exception();
- wid = this->id;
- resp = get_date_time_1(&wid, clnt(this));
+ args.id = static_cast<wespid_t>(this->id);
+ args.to_get = WESP_TIME;
+ resp = get_1(&args, clnt(this));
if (!resp)
throw connexion_exception();
if (resp->ret != WESPRET_OK)
throw_exception_using_ret(resp->ret);
- dt = &resp->dt;
+ dt = &resp->wes.current_time;
tm.tm_year = dt->year - 1900;
tm.tm_mon = dt->mon - 1;
tm.tm_mday = dt->dom;
@@ -224,9 +197,33 @@ struct tm wes_base::get_date(void)
return (tm);
}
-electricity_meter wes_base::get_electricity_meter(int em_id)
+/* ---
+ * Récupération des compteurs.
+ * --- */
+
+clamp wes_base::get_clamp(int cl_id)
+{
+ clamp cl(this, cl_id);
+
+ /* TODO: préférer la recherche */
+
+ return (cl);
+}
+
+pulse_meter wes_base::get_pulse_meter(int pl_id)
{
- electricity_meter em(this, em_id);
+ pulse_meter pm(this, pl_id);
+
+ /* TODO: préférer la recherche */
+
+ return (pm);
+}
+
+teleinfo_meter wes_base::get_teleinfo_meter(int tic_id)
+{
+ teleinfo_meter tic(this, tic_id);
+
+ /* TODO: préférer la recherche */
- return (em);
+ return (tic);
}
diff --git a/weshd.x b/weshd.x
index 476010f..f20fa3b 100644
--- a/weshd.x
+++ b/weshd.x
@@ -27,345 +27,662 @@
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL license and that you accept its terms.
* ************************************************************************* */
+/* Ce fichier est une évolution du protocole vers une utilisation des
+ * `union switch()` pour regrouper des objets entre eux. Puisque le protocole,
+ * de pair avec le logiciel, est en cours de développement, celui-ci utilise
+ * toujours la version 1 (WESHD_VERS1).
+ *
+ * Pour retrouver d'anciennes versions du protocole, reculez dans l'historique
+ * du dépôt git de développement, disponible via l'URL suivante :
+ * <https://forge.touhey.fr/usi/weshd.git>.
+ *
+ * À noter que les unions et structures dans les unions ont été principalement
+ * faites à cause des limitations de `rpcgen` : en effet, les cas dans
+ * une union ne peuvent contenir que zéro ou un membre, et les unions
+ * ne peuvent pas être définies anonymement.
+ *
+ * Notez également que contrairement au C standard, les `typedef` sont
+ * absents : cela est dû au fait que `rpcgen` les ajoute automatiquement
+ * dans les fichiers source et en-tête générés pour tout garder dans le
+ * même espace de noms. */
+
+/* ---
+ * Codes relatifs au protocole.
+ * --- */
+
/* Les codes de retour (ou d'erreur) sont les suivants :
*
- * - `WESRET_OK`: aucune erreur ;
- * - `WESRET_INT`: une erreur interne s'est produite ;
- * - `WESRET_IMP`: cette fonctionnalité n'est pas (encore) implémentée.
- * - `WESRET_VAL`: arguments invalides pour cette fonctionnalité.
+ * - `OK`: aucune erreur ;
+ * - `INT`: une erreur interne s'est produite ;
+ * - `IMP`: cette fonctionnalité n'est pas (encore) implémentée.
+ * - `VAL`: arguments invalides pour cette fonctionnalité.
+ * - `MIS`: mismatch entre ce qu'on a et ce qui est attendu par le client,
+ * utilisé pour les compteurs.
*
- * - `WESRET_NOW`: la ressource n'existe pas.
- * - `WESRET_CON`: le serveur n'a pas pu être joint. */
+ * - `NOW`: la ressource n'existe pas.
+ * - `CON`: le serveur n'a pas pu être joint.
+ * - `LRG`: la période pour la récupération de données est trop large,
+ * le statut de la (sous-)ressource a changé entretemps. */
enum wespret_t {
WESPRET_OK = 0,
WESPRET_INT = 1,
WESPRET_IMP = 2,
WESPRET_VAL = 3,
+ WESPRET_MIS = 4,
WESPRET_NOW = 10,
- WESPRET_CON = 11
+ WESPRET_CON = 11,
+ WESPRET_LRG = 12
};
-/* Un identifiant d'une ressource de type serveur WES est un entier
- * allant de 1 à 32766 inclus. */
-
-typedef int wespid_t;
+/* ---
+ * Sous-types définis pour les ressources de type serveur WES, ainsi que
+ * les autres.
+ * --- */
+
+/* Horodate, la plus complète possible pour tout couvrir.
+ * `dt` pour `datetime`, « date et heure ». */
+
+struct wespdt_t {
+ /* Date dans le calendrier grégorien.
+ * `year`: année, e.g. 2018.
+ * `mon`: mois de l'année, de 1 à 12.
+ * `dom`: jour du mois, de 1 à 31.
+ * `hour`: heure du jour, de 0 à 23.
+ * `min`: minute de l'heure, de 0 à 59.
+ * `sec`: seconde de la minute, de 0 à 60 (leap seconds). */
+
+ int year;
+ int mon;
+ int dom;
+ int hour;
+ int min;
+ int sec;
+
+ /* Jour de la semaine, de 0 à 6 pour représenter lundi à dimanche. */
+
+ int dow;
+
+ /* Fuseau horaire et option d'heure d'été.
+ * Le fuseau horaire est défini par l'heure et la minute de décalage
+ * par rapport à l'heure dans le fuseau GMT.
+ * Si le fuseau est négatif, alors l'heure sera négative.
+ * Si `dst` est vrai, alors l'heure d'été (daylight savings flag)
+ * est en vigueur. */
+
+ int tzhour;
+ int tzmin;
+ bool dst;
+};
-/* Une adresse IP, soit version 4 soit version 6. */
+/* Adresse IP (avec version). */
enum wespiptype_t {
- WESPIPTYPE_NONE = 0,
- WESPIPTYPE_4 = 4,
- WESPIPTYPE_6 = 6
+ WESPIPTYPE_4 = 4,
+ WESPIPTYPE_6 = 6
};
-struct wespip_t {
- wespiptype_t type;
- unsigned char ipv4[4];
- unsigned char ipv6[16];
+union wespip_t switch (wespiptype_t type) {
+case WESPIPTYPE_4:
+ unsigned char addr4[4];
+
+case WESPIPTYPE_6:
+ unsigned char addr6[16];
};
-/* Les données relatives à la création d'une ressource de type serveur WES.
- * - `WESPREGTYPE_DUMMY` : faire comme si un serveur WES existait, pour
- * développer une bibliothèque ou un client sans serveur WES sous la main
- * par exemple ;
- * - `WESPREGTYPE_IP` : se connecter au serveur WES via IP. */
+/* Identifiant d'un serveur WES.
+ * Cet identifiant peut aller de 1 à 32766 inclus. */
+
+typedef int wespid_t;
+
+/* Identifiant d'un compteur pour un serveur WES.
+ * Cet identifiant peut aller de 1 à 32766 inclus. */
+
+typedef int wespmeterid_t;
+
+/* Type du WES.
+ * `DUMMY`: serveur WES factice / paramètres généraux uniquement.
+ * `IP`: serveur WES connecté par IP. */
-enum wespregtype_t {
- WESPREGTYPE_DUMMY = 0,
- WESPREGTYPE_IP = 1
+enum wesptype_t {
+ WESPTYPE_DUMMY = 0,
+ WESPTYPE_NONE = 0,
+ WESPTYPE_IP = 1
};
-struct wespregopts_t {
- wespregtype_t type;
- wespip_t ip;
+/* Propriétés d'enregistrement spécifiques au serveur WES connecté par IP. */
+
+struct wespoptions_ip_t {
+ /* Propriétés spécifiques au serveur WES connecté par IP.
+ * `ip`: adresse IP.
+ * `http_username`: utilisateur HTTP.
+ * `http_password`: mot de passe HTTP.
+ * `ftp_username`: utilisateur FTP.
+ * `ftp_password`: mot de passe FTP. */
+
+ wespip_t addr;
string http_username<>;
string http_password<>;
string ftp_username<>;
string ftp_password<>;
};
-/* Une date, version protocole. */
-
-struct wespdatetime_t {
- int year; /* e.g. 2018 */
- int mon; /* 1 à 12 */
- int dom; /* 1 à 31 */
- int hour; /* 0 à 23 */
- int min; /* 0 à 59 */
- int sec; /* 0 à 60 (leap seconds) */
+/* Propriétés d'enregistrement de la ressource selon son type. */
- int dow; /* 0 à 6 (lundi à dimanche) */
- bool sum; /* « summer time » (heure d'été), 0 si heure d'hiver */
- int tz; /* e.g. `01 * 60 + 00` pour GMT+01:00 */
+union wespoptions_t switch (wesptype_t type) {
+case WESPTYPE_DUMMY:
+ /* À vrai dire, rien. C'est factice quoi. */
+case WESPTYPE_IP:
+ wespoptions_ip_t ip;
};
-/* Les données relatives au réseau. */
+/* ---
+ * Ressources de type WES.
+ * --- */
+
+/* Drapeaux pour savoir quoi définir. */
+
+const WESP_NAME = 1;
+const WESP_TIME = 2;
+
+const WESP_DHCP = 4;
+const WESP_IP = 8;
+const WESP_MASK = 16;
+const WESP_GW = 32;
+const WESP_DNS1 = 64;
+const WESP_DNS2 = 128;
+const WESP_MAC = 256;
+
+/* Propriétés pour les serveurs WES connectés via IP. */
+
+struct wespipmore_t {
+ /* Propriétés réseau. */
-struct wespnetcfg_t {
- bool enable_dhcp;
+ bool dhcp_enabled;
unsigned char ip[4];
unsigned char mask[4];
unsigned char gw[4];
unsigned char dns1[4];
unsigned char dns2[4];
+ unsigned char mac[6]; /* read-only! */
};
-struct wespnetdat_t {
- unsigned char mac[6];
+/* Propriétés diverses selon le type. */
+
+union wespmore_t switch (wesptype_t type) {
+case WESPTYPE_DUMMY:
+ /* Toujours rien. */
+case WESPTYPE_IP:
+ wespipmore_t ip;
+};
+
+/* Serveur WES. */
+
+struct wesp_t {
+ /* Propriétés à définir lors d'une affectation. */
+
+ unsigned long to_set;
+
+ /* Propriétés de base.
+ * `name`: nom de la ressource.
+ * `current_time`: temps actuel sur la ressource. */
+
+ string name<>;
+ wespdt_t current_time;
+
+ /* Autres propriétés dépendant du type. */
+
+ wespmore_t more;
+};
+
+/* ---
+ * Énumérations et sous-types divers concernant les compteurs.
+ * --- */
+
+/* De quel type de compteur s'agit-il ?
+ * `NONE`: informations génériques uniquement.
+ * `TELEINFO`: compteur branché via le protocole télé-informatique d'Enedis.
+ * `AMPER`: pinces ampèremétriques.
+ * `PULSE`: compteur d'impulsions. */
+
+enum wespmetertype_t {
+ WESPMETERTYPE_NONE = 0,
+ WESPMETERTYPE_AMPER = 1,
+ WESPMETERTYPE_PULSE = 2,
+ WESPMETERTYPE_TELEINFO = 3
+};
+
+/* Mode de consommation/production de chaque compteur.
+ * `CONSO`: consommation.
+ * `PROD`: production (panneaux solaires, …). */
+
+enum wespmetermode_t {
+ WESPMETERMODE_CONSO = 0,
+ WESPMETERMODE_PROD = 1
};
-/* Les données relatives au TÉLÉINFO.
- * BDPV est un service permettant de centraliser les informations concernant
- * les panneaux solaires, etc. */
+/* Grandeur mesurée par le compteur.
+ * `UNKNOWN`: inconnu.
+ * `WATER`: eau froide/chaude.
+ * `GAS`: gaz.
+ * `ELEC`: électricité.
+ * `FUEL`: fioul. */
+
+enum wespmeterwhat_t {
+ WESPMETERWHAT_UNKNOWN = 0,
+ WESPMETERWHAT_WATER = 1,
+ WESPMETERWHAT_GAS = 2,
+ WESPMETERWHAT_ELEC = 3,
+ WESPMETERWHAT_FUEL = 4
+};
+
+/* Unité utilisée pour les valeurs du compteur.
+ * `UNKNOWN`: Inconnu.
+ * `WH`: Watts par heure (Wh).
+ * `KWH`: Kilo-watts par heure (kWh).
+ * `LITER`: Litres (L).
+ * `CUBICMETER`: Mètres cube (m³). */
+
+enum wespmeterunit_t {
+ WESPMETERUNIT_UNKNOWN = 0,
+ WESPMETERUNIT_WH = 1,
+ WESPMETERUNIT_KWH = 2,
+ WESPMETERUNIT_LITER = 3,
+ WESPMETERUNIT_CUBICMETER = 4
+};
+
+/* Type de tarif pour le protocole télé-informatique d'ERDF.
+ * `BASE`: forfait Base (toutes heures), le prix du kWh ne varie pas en
+ * fonction de la période de consommation ;
+ * `HCHP`: forfait Heures Pleines Heures Creuses, le prix du kWh varie
+ * en fonction de l'heure de la journée ;
+ * `TEMPO`: forfait Temporaire, le prix du kWh varie en fonction de l'heure
+ * de la journée, ainsi que de la couleur de la journée ;
+ * `EJP`: forfait Effacement de Jour de Pointe, le prix du kWh varie en
+ * fonction de la journée. */
enum wesptictarif_t {
- WESPTICTARIF_BASE = 0, /* Base (toutes heures) */
- WESPTICTARIF_HCHP = 1, /* Heures Creuses, Heures Pleines */
- WESPTICTARIF_EJP = 2, /* Effacement de Jours de Pointes */
- WESPTICTARIF_TEMPO = 3 /* Temporaires (jours bleus, blancs, rouges) */
+ WESPTICTARIF_BASE = 0,
+ WESPTICTARIF_HCHP = 1,
+ WESPTICTARIF_TEMPO = 2,
+ WESPTICTARIF_EJP = 3
};
+/* Période tarifaire pour le protocole télé-informatique d'ERDF.
+ * La signification des valeurs dans cette énumération dépend du forfait
+ * souscrit pour ce compteur.
+ * Cette structure est pensée comme un champ de bits puisque les
+ * valeurs peuvent couvrir plusieurs périodes.
+ *
+ * Forfait BASE :
+ * `TH`: toutes heures.
+ *
+ * Forfait HCHP :
+ * `HC`: heures creuses.
+ * `HP`: heures pleines.
+ *
+ * Forfait TEMPO :
+ * `HC`: heures creuses.
+ * `HP`: heures pleines.
+ * `JB`: jours bleus.
+ * `JW`: jours blancs.
+ * `JR`: jours rouges.
+ *
+ * Forfait EJP :
+ * `HN`: heures normales.
+ * `PM`: pointes mobiles. */
+
enum wespticperiod_t {
- WESPTICPERIOD_HN = 0, /* Heures Normales/Toutes les Heures */
- WESPTICPERIOD_HC = 1, /* Heures Creuses (HCHP) */
- WESPTICPERIOD_HP = 2, /* Heures Pleines (HCHP) */
- WESPTICPERIOD_PM = 3, /* Heures de Pointe Mobile (EJP) */
+ WESPTICPERIOD_TH = 1,
- WESPTICPERIOD_JB = 0, /* Jours Bleus */
- WESPTICPERIOD_JW = 4, /* Jours Blancs */
- WESPTICPERIOD_JR = 8, /* Jours Rouges */
+ WESPTICPERIOD_HC = 1,
+ WESPTICPERIOD_HP = 2,
- WESPTICPERIOD_HCJB = 1, /* Heures Creuses Jours Bleus */
- WESPTICPERIOD_HPJB = 2, /* Heures Pleines Jours Bleus */
- WESPTICPERIOD_HCJW = 5, /* Heures Creuses Jours Blancs */
- WESPTICPERIOD_HPJW = 6, /* Heures Pleines Jours Blancs */
- WESPTICPERIOD_HCJR = 9, /* Heures Creuses Jours Rouges */
- WESPTICPERIOD_HPJR = 10 /* Heures Pleines Jours Rouges */
-};
+ WESPTICPERIOD_JB = 4,
+ WESPTICPERIOD_JW = 8,
+ WESPTICPERIOD_JR = 16,
-enum wespticmode_t {
- WESPTICMODE_CONSO = 0, /* consommation */
- WESPTICMODE_PROD = 1 /* production */
+ WESPTICPERIOD_HN = 1,
+ WESPTICPERIOD_PM = 2
};
-enum wespticphmode_t {
- WESPTICPHMODE_NONE = 0, /* Aucun */
- WESPTICPHMODE_MONO = 1, /* Monophasé */
- WESPTICPHMODE_TRI = 3 /* Triphasé */
+/* Méthode de mesure pour les compteurs à impulsions.
+ * `ILS`: impulsions mécaniques.
+ * `ELEC`: impulsions électroniques. */
+
+enum wespplsmethod_t {
+ WESPPLSMETHOD_ILS = 0,
+ WESPPLSMETHOD_ELEC = 1
};
-struct wespticcfg_t {
- /* Propriétés de base du compteur. */
+/* Drapeaux pour savoir quoi définir ou ce qui est défini. */
- bool read; /* Le compteur est-il actif ? */
- wespticmode_t mode; /* Mode CONSO ou PRODUCTION */
- string name<>; /* Quel nom a été donné au compteur ? */
+const WESPMETER_NAME = 1;
+const WESPMETER_READ = 2;
+const WESPMETER_MODE = 4;
+const WESPMETER_WHAT = 8;
+const WESPMETER_TYPE = 16;
+const WESPMETER_FIXED_COSTS = 32;
+const WESPMETER_PRORATA = 64;
- /* Propriétés tarifaires. */
+const WESPMETER_COST = 128;
+const WESPMETER_VOLTAGE = 256;
- double abo; /* Coût de l'abonnement annuel */
- bool prorata; /* Prorata abonnement au prix du kWh ou non ? */
+const WESPMETER_METHOD = 256;
+const WESPMETER_GROUP = 512;
- /* Tarif appliqué pour l'abonnement BASE. */
+const WESPMETER_COSTS_BASE = 128;
+const WESPMETER_COSTS_HCHP = 256;
+const WESPMETER_COSTS_TEMPO = 512;
+const WESPMETER_COSTS_EJP = 1024;
+const WESPMETER_BDPV_ENABLED = 2048;
+const WESPMETER_BDPV_IDS = 4096;
+const WESPMETER_BDPV_TIME = 8192;
- double tarif_base;
+/* ---
+ * Structures concernant les compteurs.
+ * --- */
- /* Tarifs appliqués pour l'abonnement HCHP (heures creuses h. pleines). */
+struct wespmetermore_amper_t {
+ /* Propriétés relatives aux compteurs de type pinces ampèremétriques.
+ * `voltage`: voltage (en V). */
- double tarif_hchp_hc;
- double tarif_hchp_hp;
+ int voltage;
- /* Tarifs appliqués pour l'abonnement TEMPO (jours bleus, blancs, rouges,
- * heures creuses et pleines). */
+ /* Propriétés tarifaires.
+ * `cost`: coût de l'unité. */
- double tarif_tempo_hcjb;
- double tarif_tempo_hpjb;
- double tarif_tempo_hcjw;
- double tarif_tempo_hpjw;
- double tarif_tempo_hcjr;
- double tarif_tempo_hpjr;
+ double cost;
+};
- /* Tarifs appliqués pour l'abonnement EJP (Effacement de Jour de
- * Pointe). */
+struct wespmetermore_pulse_t {
+ /* Propriétés relatives aux compteurs de type impulsions.
+ * `method`: méthode de comptage d'impulsions.
+ * `group_size`: taille d'un groupe d'impulsions pour faire une unité. */
- double tarif_ejp_hn; /* Heures Normales */
- double tarif_ejp_pm; /* Pointe Mobile */
+ wespplsmethod_t method;
+ int group_size;
- /* Si les résultats sont envoyés au site BDPV. */
+ /* Propriétés tarifaires.
+ * `cost`: coût de l'unité. */
+
+ double cost;
+};
+
+struct wespmetermore_teleinfo_t {
+ /* Propriétés relatives aux compteurs branchés via
+ * le protocole télé-information défini par Enedis.
+ * `cost_<abo>_<période>`: coût du kWh pendant une période lorsqu'un
+ * forfait est actuellement en vigueur.
+ * `bdpv_enabled`: envoyer (ou non) les données via BDPV.
+ * `bdpv_hour`: heure d'envoi via BDPV.
+ * `bdpv_min`: minutes d'envoi via BDPV. */
+
+ double cost_base_th;
+ double cost_hchp_hc;
+ double cost_hchp_hp;
+ double cost_tempo_hcjb;
+ double cost_tempo_hpjb;
+ double cost_tempo_hcjw;
+ double cost_tempo_hpjw;
+ double cost_tempo_hcjr;
+ double cost_tempo_hpjr;
+ double cost_ejp_hn;
+ double cost_ejp_pm;
bool bdpv_enabled;
int bdpv_hour;
int bdpv_min;
+ string bdpv_username<>;
+ string bdpv_password<>;
};
-struct wespticdat_t {
- bool plugged_in; /* Le compteur est-il branché ? */
- bool standing_by; /* Le compteur est-il en mode veille ? */
+union wespmetermore_t switch (wespmetertype_t type) {
+case WESPMETERTYPE_NONE:
+ /* Aucun paramètre supplémentaire. */
+case WESPMETERTYPE_AMPER:
+ wespmetermore_amper_t amper;
+case WESPMETERTYPE_PULSE:
+ wespmetermore_pulse_t pulse;
+case WESPMETERTYPE_TELEINFO:
+ wespmetermore_teleinfo_t teleinfo;
+};
- /* Propriétés relatives au TÉLÉINFO. */
+/* Structure représentant un compteur (branché via télé-informatique,
+ * pinces ampèremétriques, impulsions). */
- unsigned char adco[12]; /* Identification du compteur */
- wesptictarif_t tarif; /* Type de tarif */
- wespticphmode_t phmode; /* Mode de l'entrée (monophasé ou triphasé) */
- wespticperiod_t period; /* Période tarifaire en cours */
+struct wespmeter_t {
+ /* Propriétés de base de tout compteur.
+ * `name`: nom du compteur tel que défini par le système distant.
+ * `rd`: le compteur est-il lu ou ignoré par le système ?
+ * `mode`: mode de consommation/production du compteur.
+ * `what`: grandeur mesurée. */
- /* Intensités, puissances. */
+ string name<>;
+ bool rd;
+ wespmetermode_t mode;
+ wespmeterwhat_t what;
- unsigned int isousc; /* Intensité souscrite */
- unsigned int pa; /* Puissance apparente (VA). */
- unsigned int iinst[3]; /* Intensité instantanée pour chaque phase */
- unsigned int imax[3]; /* Intensité maximale pour chaque phase */
+ /* Informations concernant le coût.
+ * `fixed_cost`: coût fixe de l'abonnement, à l'année.
+ * `prorata`: l'abonnement est-il au prorata du prix de l'unité ? */
- /* Index pour l'abonnement BASE. */
+ double fixed_cost;
+ bool prorata;
- unsigned long index_base;
+ /* Informations dépendant du type. */
- /* Index pour l'abonnement HCHP (heures creuses h. pleines). */
+ wespmetermore_t more;
+};
- unsigned long index_hchp_hc;
- unsigned long index_hchp_hp;
+/* Valeurs du compteur pour une période donnée. */
- /* Index pour l'abonnement TEMPO (jours bleus, blancs, rouges,
- * heures creuses et pleines). */
+struct wespmetermorevalues_index_base_t {
+ unsigned long th;
+};
- unsigned long index_tempo_hcjb;
- unsigned long index_tempo_hpjb;
- unsigned long index_tempo_hcjw;
- unsigned long index_tempo_hpjw;
- unsigned long index_tempo_hcjr;
- unsigned long index_tempo_hpjr;
+struct wespmetermorevalues_index_hchp_t {
+ unsigned long hc;
+ unsigned long hp;
+};
- /* Index pour l'abonnement EJP (Effacement de Jour de
- * Pointe). */
+struct wespmetermorevalues_index_tempo_t {
+ unsigned long hcjb;
+ unsigned long hpjb;
+ unsigned long hcjw;
+ unsigned long hpjw;
+ unsigned long hcjr;
+ unsigned long hpjr;
+};
- unsigned long index_ejp_hn; /* Heures Normales */
- unsigned long index_ejp_pm; /* Pointe Mobile */
+struct wespmetermorevalues_index_ejp_t {
+ unsigned long hn;
+ unsigned long pm;
};
-/* Structures utiles aux appels serveur. */
+union wespmetermorevalues_index_t switch (wesptictarif_t tarif) {
+case WESPTICTARIF_BASE:
+ wespmetermorevalues_index_base_t base;
+case WESPTICTARIF_HCHP:
+ wespmetermorevalues_index_hchp_t hchp;
+case WESPTICTARIF_TEMPO:
+ wespmetermorevalues_index_tempo_t tempo;
+case WESPTICTARIF_EJP:
+ wespmetermorevalues_index_ejp_t ejp;
+};
-struct wespret_with_id_t {
- wespret_t ret;
- wespid_t id;
- string name<>;
+struct wespmetermorevalues_teleinfo_t {
+ /* Données relatives à un compteur branché via TÉLÉINFO.
+ * Si plusieurs compteurs ou plusieurs forfaits ont été connus
+ * sur la période donnée, l'erreur `WESPRET_LRG` sera renvoyée.
+ *
+ * `adco`: numéro ADCO du compteur (un chiffre direct par case).
+ * `phases`: nombre de phases (monophasé : 1, triphasé : 3).
+ * `period`: périodes tarifaires sur la période.
+ * `isousc`: intensité souscrite.
+ * `pa`: puissance apparente (en VA).
+ * `iinst`: intensité instantanée pour chaque phase.
+ * `imax`: intensité maximale pour chaque phase. */
+
+ unsigned char adco[12];
+ int phases;
+ wespticperiod_t period;
+
+ unsigned int isousc;
+ unsigned int pa;
+ unsigned int iinst[3];
+ unsigned int imax[3];
+
+ /* Index pour chacun des tarifs, avec le tarif en vigueur. */
+
+ wespmetermorevalues_index_t indexes;
};
-struct wespret_with_datetime_t {
- wespret_t ret;
- wespdatetime_t dt;
+union wespmetermorevalues_t switch (wespmetertype_t type) {
+case WESPMETERTYPE_TELEINFO:
+ wespmetermorevalues_teleinfo_t teleinfo;
};
-struct wespid_with_datetime_t {
+struct wespmetervalues_t {
+ /* Valeur avec unité récupérée pour cette période.
+ * `active`: le compteur a-t-il été actif (branché, envoyant des valeurs)
+ * pour cette période ?
+ * `count`: nombre d'unités détectées pendant cette période.
+ * `unit`: unité de mesure pour la valeur précédente. */
+
+ bool active;
+ double count;
+ wespmeterunit_t unit;
+
+ /* Davantage de valeurs selon le type. */
+
+ wespmetermorevalues_t more;
+};
+
+/* ---
+ * Structures pour utilisation par le programme.
+ * --- */
+
+/* Gestion des serveurs WES. */
+
+struct wespid_with_wes_t {
wespid_t id;
- wespdatetime_t dt;
+ wesp_t wes;
};
-struct wespid_with_ntp_t {
+struct wespid_with_wes_flags_t {
wespid_t id;
- string ntpserver<>;
+ unsigned long to_get;
};
-struct wespid_with_hostname_t {
+struct wespquery_t {
+ int offset;
+ int count; /* min. 1, max. 10 ! */
+};
+
+struct wespret_with_id_t {
+ wespret_t ret;
wespid_t id;
- string hostname<>;
+ string name<>;
};
-struct wespret_with_hostname_t {
+struct wespret_with_wes_t {
wespret_t ret;
- string hostname<>;
+ wesp_t wes;
};
-struct wespret_with_net_t {
+struct wespret_with_wes_list_t {
wespret_t ret;
- wespnetcfg_t cfg;
- wespnetdat_t data;
+ wesp_t wes<>;
};
-struct wespid_with_net_t {
+/* Gestion des compteurs. */
+
+struct wespid_with_meter_id_t {
wespid_t id;
- wespnetcfg_t cfg;
+ wespmeterid_t meter_id;
+ wespmetertype_t expected_type;
+ unsigned long to_get;
};
-struct wespid_with_ids_t {
+struct wespid_with_meter_t {
wespid_t id;
- string username<>;
- string password<>;
+ wespmeterid_t meter_id;
+ wespmeter_t meter;
};
-struct wespid_with_tic_id_t {
+struct wespid_with_meter_id_and_span_t {
wespid_t id;
- int tic_id;
+ wespmeterid_t meter_id;
+ wespdt_t from;
+ wespdt_t to; /* not included! */
};
-struct wespid_with_tic_id_and_time_t {
+struct wespid_with_meter_query_t {
wespid_t id;
- int tic_id;
- wespdatetime_t dt;
+ wespmetertype_t of_type;
+ int offset;
+ int count; /* min. 1, max. 10 ! */
};
-struct wespid_with_tic_t {
- wespid_t id;
- int tic_id;
- wespticcfg_t cfg;
+struct wespret_with_meter_t {
+ wespret_t ret;
+ wespmeter_t meter;
};
-struct wespret_with_tic_t {
+struct wespret_with_meter_data_t {
wespret_t ret;
- wespticcfg_t cfg;
- wespticdat_t data;
+ wespmetervalues_t val;
};
-struct wespret_with_ticdata_t {
+struct wespmeter_list_element_t {
+ wespmeterid_t id;
+ wespmetertype_t type;
+};
+
+struct wespret_with_meter_list_t {
wespret_t ret;
- wespticdat_t data;
+ wespmeter_list_element_t meters<>;
};
-/* Voici la définition du programme en lui-même. */
+/* ---
+ * Définition du programme.
+ * --- */
program WESHD_PROG {
version WESHD_VERS1 {
- /* Gérer les ressources existantes. */
-
- wespret_with_id_t gather(wespregopts_t args) = 1;
- wespret_t unregister(wespid_t id) = 2;
+ /* Fonction qui ne fait rien, pour pinger le service. */
- /* Récupérer et définir le nom d'hôte du serveur WES. */
+ void WESHD_NULL(void) = 0;
- wespret_with_hostname_t get_host_name(wespid_t id) = 3;
- wespret_t set_host_name(wespid_with_hostname_t id) = 4;
+ /* Gérer les serveur WES. */
- /* Gérer les identifiants du serveur WES (si l'interface
- * l'utilise). */
+ wespret_with_id_t GATHER(wespoptions_t args) = 1;
+ wespret_t UNREGISTER(wespid_t id) = 2;
- wespret_t set_http_ids(wespid_with_ids_t id) = 5;
- wespret_t set_ftp_ids(wespid_with_ids_t id) = 6;
+ wespret_with_wes_t GET(wespid_with_wes_flags_t id) = 3;
+ wespret_t SET(wespid_with_wes_t id) = 4;
+ wespret_with_wes_list_t
+ QUERY_WES(wespquery_t args) = 5;
- /* Gérer l'heure du serveur WES. */
+ /* Gérer les compteurs. */
- wespret_with_datetime_t get_date_time(wespid_t id) = 16;
- wespret_t set_date_time(wespid_with_datetime_t id) = 17;
-#if 0
- wespret_t set_ntp(wespid_with_ntp_t id) = 18;
- wespret_t enable_ntp(wespid_t id) = 19;
- wespret_t disable_ntp(wespid_t id) = 20;
-#endif
-
- /* Gérer l'aspect réseau du WES. */
-
- wespret_with_net_t get_network(wespid_t id) = 21;
- wespret_t set_network(wespid_with_net_t id) = 22;
+ wespret_with_meter_t GET_METER(wespid_with_meter_id_t id) = 6;
+ wespret_t SET_METER(wespid_with_meter_t id) = 7;
+ wespret_with_meter_data_t
+ GET_METER_DATA(wespid_with_meter_id_and_span_t args) = 8;
+ wespret_with_meter_list_t
+ QUERY_METERS(wespid_with_meter_query_t args) = 9;
- /* Gérer les compteurs branchés via TÉLÉINFO. */
-
- wespret_with_tic_t get_tic(wespid_with_tic_id_t id) = 23;
- wespret_with_ticdata_t
- get_tic_values(wespid_with_tic_id_and_time_t args) = 24;
- wespret_t set_tic(wespid_with_tic_t id) = 25;
+ /* TODO: interactions avec le LCD */
} = 1;
} = 0x20001234;
+/* Puisque `rpcgen` ne définit pas, de base, dans le fichier d'en-tête,
+ * la fonction correspondant au serveur, et que nous souhaitons nous en
+ * servir, nous la définissons ici. */
+
#ifdef RPC_HDR
%extern void weshd_prog_1(struct svc_req *rqstp, SVCXPRT *transp);
#endif