Xpl-vmc.c

De MicElectroLinGenMet.

Source du programme xpl-vmc

Programme C pour piloter une VMC par bus 1-wire et messages Xpl.


/* xpl-vmc */
 
/*  5/10/2009 
Arrét/marche lente/rapide de la VMC en fonction de l'humidité salle de bain (sonde Oregon)
 
-----------------------------------------------------------------------------------
Messages xPL utilisés:
 
En écoute état senseur: 
SENSOR.BASIC 
sensor.basic { device='thgr228n.32' type='humidity' current='43' string='comfortable' }
 
Commande/statut état VMC:
HVAC.BASIC (heating, ventilation and air-conditioning) devices
http://xplproject.org.uk/wiki/index.php/Schema_-_HVAC
 
-----------------------------------------------------------------------------------
Arrét/marche lente/rapide de la VMC
$ xpl-sender -m xpl-cmnd -c hvac.basic command=fan-mode zone=SdB mode=Off/OnHigh/OnLow/AutoHigh/AutoLow
 
 
-----------------------------------------------------------------------------------
Envoie de message Trigger en response aux messages hvac.basic. 
hvac.zone
{
	zone=id
	hvac-mode=
	fan-mode=
	timer-mode=
	hvac-state=
	fan-state=
	temperature=#
}
 
HVAC.ZONE signale changement état ventilation.
xpl-trig
{
	hop=1
	source=domos-xplvmc.vesta
	target=*
}
hvac.zone
{
	zone=SdB
	fan-mode=Off/OnHigh/OnLow/AutoHigh/AutoLow
	humidity=h%sdb
}
 
-----------------------------------------------------------------------------------
Demande état de la zone SdB
$ xpl-sender -m xpl-cmnd -c hvac.request request=zone zone=SdB
 
hvac.request
{
request=gateinfo|zonelist|zoneinfo|zone|setpoint|timer|runtime|fantime
zone=id
[setpoint=]
[state=]
}
 
---------------
Envoie de message Status en response aux messages hvac.request. 
xpl-stat
{
	hop=1
	source=domos-xplvmc.vesta
	target=*
}
hvac.zone
{
	zone=SdB
	fan-mode=Off/OnHigh/OnLow/AutoHigh/AutoLow
	humidity=h%sdb
}
 
 
-----------------------------------------------------------------------------------
Log du programme en fonctionnement.
 
Oct 18 19:07:19 vesta xpl-vmc[789]: Démarrage ...
Oct 18 20:03:11 vesta xpl-vmc[789]: Humidité SdB trop élévée !
Oct 18 20:03:11 vesta xpl-vmc[789]: Commande VMC en mode: 2.
Oct 18 20:55:11 vesta xpl-vmc[789]: Humidité SdB revenue  à la normale !
Oct 18 20:55:11 vesta xpl-vmc[789]: Commande VMC en mode: 1.
 
*/
 
//---------------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <syslog.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <signal.h> 
#include <owcapi.h>
#include <xPL.h>
#include "xpl-vmc.h"
 
#define	ON  '1'
#define	OFF '0'
#define	VRAI 1
#define	FAUX 0
 
 
// Déclarations gestion programme
int 		finprog = 0 ;
int 		debug = 0 ;
 
// Déclarations pour l'heure
time_t 		td;
struct 	tm 	*dc;
char		sdate[12];
char		sheure[10];
 
// Déclarations pour xPL.
#define XPL_VERSION "20091005"
xPL_ServicePtr 	DomosService ;
xPL_MessagePtr 	DomosMessageStat ;
xPL_MessagePtr 	DomosMessageTrig ;
 
// Déclarations pour la sonde
#define	SONDESDB "thgr228n.32"
char svalhumidity[4] = "0" ;
 
// Déclarations pour gestion VMC
int 		autovmc   = VRAI ;
int 		stopvmc   = FAUX ;
int 		speed2vmc = FAUX ;
 
// Déclarations pour OWFS.
#define	OWHOST 		  "localhost:4304"
#define OWOUTPUTVMCSTOP   "/12.29435F000000/PIO.A"
#define OWOUTPUTVMCSPEED2 "/12.8B515F000000/PIO.A"
 
 
/* ------------------------------------------------------------------------------------	*/
/* Fonctions xPL								 	*/
/* ------------------------------------------------------------------------------------ */
int init_xpl(void)
{
 //xPL_setDebugging(TRUE) ;
 
 // Start xPL up
 if ( !xPL_initialize(xPL_getParsedConnectionType()) ) return 0 ;
 
 // Create  a service
 DomosService = xPL_createService("domos", "xplvmc", "vesta");
 xPL_setServiceVersion(DomosService, XPL_VERSION);
 
 // Add responder(s)
 // Ajout fonction écoute sensor.basic (état senseur SdB)
 xPL_addServiceListener(DomosService, DomosMessageSensorBasicHandler, xPL_MESSAGE_TRIGGER, "sensor", "basic", NULL) ;
 // Ajout fonction écoute hvac.basic (commande VMC)
 xPL_addServiceListener(DomosService, DomosMessageHvacBasicHandler, xPL_MESSAGE_COMMAND, "hvac", "basic", NULL) ;
 
 
 // Create a message to send
 DomosMessageStat = xPL_createBroadcastMessage(DomosService, xPL_MESSAGE_STATUS) ;
 DomosMessageTrig = xPL_createBroadcastMessage(DomosService, xPL_MESSAGE_TRIGGER) ;
 
 // Enable the service
 xPL_setServiceEnabled(DomosService, TRUE);
 
 return 1 ;
}
 
/* ------------------------------------------------------------------------------------ */
// Traite message sensor.basic (trig)
// sensor.basic { device='thgr228n.32' type='humidity' current='45' string='comfortable' }
void DomosMessageSensorBasicHandler(xPL_ServicePtr theService, xPL_MessagePtr theMessage, xPL_ObjectPtr userValue)
{
	xPL_NameValueListPtr ListNomsValeursPtr ;
	char device[255] ;
	char type[255] ;
	char mode[255] ;
	float valhumidity ;
 
	if ( (autovmc) || (! stopvmc) )
	{
		ListNomsValeursPtr = xPL_getMessageBody(theMessage) ;
		strcpy(device, (xPL_getNamedValue(ListNomsValeursPtr, "device")) ) ;
 
		if ( strstr(device, SONDESDB) != NULL ) 
		{
			strcpy(type, (xPL_getNamedValue(ListNomsValeursPtr, "type")) ) ;
			if ( strstr(type, "humidity") != NULL ) 
			{
				if (debug) PrintMessageInfo(theMessage, ListNomsValeursPtr) ;
				strcpy(svalhumidity, (xPL_getNamedValue(ListNomsValeursPtr, "current")) ) ;
				valhumidity = atoi(svalhumidity) ;
				if ( ( ! speed2vmc) && (valhumidity > 65) )
				{
					syslog(LOG_INFO, "Humidité SdB trop élévée (%f%%) !", valhumidity) ;
					if ( setmodevmc(2) )
						SendHvacZoneXpl("trig", "OnHigh", svalhumidity) ;		
				}
				if ( ( speed2vmc) && (valhumidity < 64) )
				{
					syslog(LOG_INFO, "Humidité SdB revenue à la normale (%f%%) !", valhumidity) ;
					if ( setmodevmc(1) )
						SendHvacZoneXpl("trig", "OnLow", svalhumidity) ;		
				}
			}
		}
	}
}
 
/* ------------------------------------------------------------------------------------ */
// Traite message hvac.basic (cmd)
// hvac.basic command=fan-mode zone=SdB mode=Off/OnHigh/OnLow/AutoHigh/AutoLow
void DomosMessageHvacBasicHandler(xPL_ServicePtr theService, xPL_MessagePtr theMessage, xPL_ObjectPtr userValue)
{
	xPL_NameValueListPtr ListNomsValeursPtr ;
	char commande[255] ;
	char zone[255] ;
	char mode[255] ;
 
	ListNomsValeursPtr = xPL_getMessageBody(theMessage) ;
 
	strcpy(commande, (xPL_getNamedValue(ListNomsValeursPtr, "command")) ) ;
	if ( strstr(commande, "fan-mode") != NULL ) 
	{
		if (debug) PrintMessageInfo(theMessage, ListNomsValeursPtr) ;
		strcpy(zone, (xPL_getNamedValue(ListNomsValeursPtr, "zone")) ) ;
		if ( strstr(zone, "SdB") != NULL ) 
		{
			strcpy(mode, (xPL_getNamedValue(ListNomsValeursPtr, "mode")) ) ;
			if ( strstr(mode, "Off") != NULL ) 
			{
				if ( setmodevmc(0) )
					SendHvacZoneXpl("trig", "Off", svalhumidity) ;	
			}
			else
			if ( strstr(mode, "OnLow") != NULL ) 
			{
				if ( setmodevmc(1) )
					SendHvacZoneXpl("trig", "OnLow", svalhumidity) ;	
			}
			//else
		}
	}
}
 
/* ------------------------------------------------------------------------------------ */
/* Envoie messages									*/
/* ------------------------------------------------------------------------------------ */
// Envoi message: xpl-stat/xpl-trig hvac.zone (état vmc)
void SendHvacZoneXpl(char *msgtype, char *mode, char *hum)
{
  if (strcmp(msgtype, "stat") == 0)
  {
  	xPL_setSchema(DomosMessageStat, "hvac", "zone");
    	// Install the value(s) and send the message
  	xPL_setMessageNamedValue(DomosMessageStat, "zone", "SdB");
  	xPL_setMessageNamedValue(DomosMessageStat, "fan-mode", mode);
  	xPL_setMessageNamedValue(DomosMessageStat, "humidity", hum);
  	// Broadcast the message
  	xPL_sendMessage(DomosMessageStat);
  }
  else
  {
  	xPL_setSchema(DomosMessageTrig, "hvac", "zone");
    	// Install the value(s) and send the message
  	xPL_setMessageNamedValue(DomosMessageTrig, "zone", "SdB");
  	xPL_setMessageNamedValue(DomosMessageTrig, "fan-mode", mode);
  	xPL_setMessageNamedValue(DomosMessageTrig, "humidity", hum);
  	// Broadcast the message
  	xPL_sendMessage(DomosMessageTrig);
  }
}
 
/* ------------------------------------------------------------------------------------ */
// Affiche sur sdtout message xPL reçu (pour debug)
void PrintMessageInfo(xPL_MessagePtr theMessage, xPL_NameValueListPtr ListNomsValeursPtr)
{
  xPL_NameValuePairPtr NomValeurPtr = NULL;
  int NameValueIndex ;
  int NameValueCount ;
 
  printf("Received Message from %s-%s.%s type ",
	  xPL_getSourceVendor(theMessage), xPL_getSourceDeviceID(theMessage), xPL_getSourceInstanceID(theMessage));
 
  switch(xPL_getMessageType(theMessage)) {
  case xPL_MESSAGE_COMMAND:
    printf("xpl-cmnd ");
    break;
  case xPL_MESSAGE_STATUS:
    printf("xpl-stat ");
    break;
  case xPL_MESSAGE_TRIGGER:
    printf("xpl-trig ");
    break;
  default:
    printf("UNKNOWN ");
    break;
  }
 
  printf("for %s.%s: ", xPL_getSchemaClass(theMessage), xPL_getSchemaType(theMessage));
 
  // Write Name/Value Pairs received out
  NameValueCount = xPL_getNamedValueCount(ListNomsValeursPtr) ;
  for (NameValueIndex = 0; NameValueIndex < NameValueCount; NameValueIndex++)
  {
    NomValeurPtr = xPL_getNamedValuePairAt(ListNomsValeursPtr, NameValueIndex);
    printf("%s=", NomValeurPtr->itemName);
 
    /* Write data content out */
    if (NomValeurPtr->itemValue != NULL) printf("'%s' ", NomValeurPtr->itemValue);
  }
  printf("\n") ;
}
 
/* ------------------------------------------------------------------------------------ */
void shutdown_xpl(void)
{
 xPL_setServiceEnabled(DomosService, FALSE) ;
 xPL_releaseService(DomosService) ;
 xPL_shutdown() ;
}
 
 
/* ------------------------------------------------------------------------------------ */
/* Fonction OW										*/
/* ------------------------------------------------------------------------------------ */
int setowoutput(char *output, char val)
{
	if (debug) printf("Output=%s, val=%c\n", output, val) ;
	if ( OW_put(output, &val, 1) < 0 )
	{
		sleep(1) ;
		if ( OW_put(output, &val, 1) < 0 )	// Deuxième essai.
		{
			syslog(LOG_ERR,"Erreur écriture senseur %s (essai 2) : %s\n", output, strerror(errno));
			return 0 ;
		}
	}
	return 1 ;
}
 
/* ------------------------------------------------------------------------------------ */
/* Fonction commande VMC (Off=0 /OnLow=1 /OnHigh=2)					*/
/* ------------------------------------------------------------------------------------ */
int setmodevmc(int speed)
{
	syslog(LOG_INFO, "Commande VMC en mode: %d.", speed) ;
	switch (speed) 
	{
		case 0: 
			if ( setowoutput(OWOUTPUTVMCSTOP, ON) )
			{
				stopvmc = VRAI ;
				return 1 ;
			}
			else return 0 ;
			break ;
		case 1: 
			if (stopvmc) if ( ! setowoutput(OWOUTPUTVMCSTOP, OFF) ) return 0 ;
			stopvmc = FAUX ;
			if ( setowoutput(OWOUTPUTVMCSPEED2, OFF) )
			{
				speed2vmc = FAUX ;
				return 1 ;
			}
			else return 0 ;
			break;
		case 2: 
			if (stopvmc) if ( ! setowoutput(OWOUTPUTVMCSTOP, OFF) ) return 0 ;
			stopvmc = FAUX ;
			if ( setowoutput(OWOUTPUTVMCSPEED2, ON) )
			{
				speed2vmc = VRAI ;
				return 1 ;
			}
			else return 0 ;
			break;
	}
	return 0 ;
}
 
/* ------------------------------------------------------------------------------------ */
/* Fonctions interruptions     								*/
/* ------------------------------------------------------------------------------------ */
void init_interruptions_signal(void)
{
	signal(SIGHUP, &signal_handler);		// Intercepte les signaux pour quitter le prog. proprement.
	signal(SIGINT, &signal_handler);		// Fonction 'signal_handler' appelée.
	signal(SIGTERM, &signal_handler);
	signal(SIGQUIT, &signal_handler);
}
 
/* ------------------------------------------------------------------------------------ */
void signal_handler(int signum)
{
        switch(signum)
        {
                case SIGINT:
                case SIGQUIT:
                case SIGTERM:
			syslog(LOG_INFO, "Abandon programme demandé. !") ;
			finprog = 1 ;
                        break;
                case SIGHUP:
			syslog(LOG_INFO, "Réactivation programme demandée. !") ;
                        break ;
        }
}
 
 
 
/* ------------------------------------------------------------------------------------	*/
/* MAIN										 	*/
/* ------------------------------------------------------------------------------------ */
int main ( int argc, char ** argv )
{
 
 init_interruptions_signal() ;
 
 openlog("xpl-vmc", LOG_PID, LOG_USER) ;
 syslog(LOG_INFO, "Démarrage ...") ;
 
 // Init xPL.
 if ( ! init_xpl() )
 {
	syslog(LOG_ERR, "Erreur lancement xPL ! ");
	closelog() ;
	exit(1) ;
 }
 
 if ( OW_init(OWHOST) != 0)
 {
	syslog(LOG_ERR, "Erreur init OWFS : %s\n", strerror(errno)) ;
	OW_finish() ;
	exit(1) ;
 }
 
 // Boucle principale.
 do
 {
	xPL_processMessages(100) ;
	usleep(10000) ;
 }
 while (! finprog) ;
 
 setmodevmc(1) ;				// Vitesse VMC normale.
 // Fermeture xPL.
 syslog(LOG_INFO, "Arrêt couche xPL !") ;
 shutdown_xpl() ;
 syslog(LOG_INFO, "Arrêt connexion OWFS !") ;
 OW_finish() ;
 
 syslog(LOG_INFO, "Fin programme.") ;
 closelog() ;
 exit (0) ;
}
/* ------------------------------------------------------------------------------------ */