CPF Alert nella Qsysopr, notifica il mio Iphone … o accendi una luce … o fai partire la lavatrice !

1
384

IFTTTForse non tutti la conoscono ma l’applicazione IFTTT If This Than That, è veramente fantastica per collegare eventi tra applicazioni, cose, spazi … al succedere di un determinato evento fai/esegui qualcosa.

Io, ad esempio, la uso per memorizzare i like dei Tweets in un Google Docs o anche per registrare nel mio Google Calendar orari di entrata/uscita dalle sedi dei miei clienti … o un sacco di altre cose configurando semplicemente apposite “Recipes” su IFTTT.

E allora perchè no ? Perchè non integrare le fantastiche funzionalità di IFTTT con il mio IBMi ?

Partiamo da una idea semplice ma utile: un programma che monitora la coda QSYSOPR … quando trova determinati CPF importanti attiva una notifica sul mio Iphone e su quello del Responsabile IT.

Continua a leggere qui sotto per vedere passo passo come fare:

IFTTT Account e Maker_to_IosNotification recipe di base

Per prima cosa bisogna creare una account di IFTTT, gratis, attivare il Channel MAKER, recuperarne la Key e creare una piccola “recipe IFTTT”:

  1. Creare un free account su IFTTT
  2. Collegare il canale Maker all’account prendendo nota della apposita KEY assegnata
  3. Creare una nuova “Recipe” utilizzando il Canale “MAKER”
    1. Then: Receive a Web Request
    2. Then: Event name=”IBMi_Message” (o quello che vuoi tu come nome evento)
    3. That : Ios Notification (o Android Notification o Philips Hue Lamp o quello che vuoi)
    4. That: Testo della notifica: “{{EventName}}” CPF “{{value1}}” “{{value2}}” severity “{{value3}}”
    5. “Create an action”
  4. Da qui in avanti installiamo e compiliamo i sorgenti di questo articolo come spiegato nella sezione che segue.

 

MONQSOMS2 CLLE program

Poi creiamo un sorgente CLLE nella nostra libreria e copiamo e compiliamo il seguente sorgente … che non fa altro che restare in attesa di un messaggio dalla QSYSOPR per tornarlo al programma chiamante MONQSOMS1 (vedi capitolo successivo).

&MSGID &SEV &SENDER &RTNTYPE &ALROPT &MSGF &MSGFLIB &SNDMSGFLIB)
DCL &KEYVAR *CHAR 4
DCL &MSGL1 *CHAR 100 /* FIRST LEVEL TEXT*/
DCL &MSGL1LEN *DEC (5 0) /* AND ITS LENGTH*/
DCL &MSGL2 *CHAR 100 /* SECOND LEVEL TEXT */
DCL &MSGL2LEN *DEC (5 0) /* AND ITS LENGTH */
DCL &MSGDTA *CHAR 100 /* MESSAGE DATA */
DCL &MSGDTALEN *DEC (5 0) /* AND ITS LENGTH */
DCL &MSGID *CHAR 7 /* MESSAGE ID */
DCL &SEV *DEC (2 0) /* MESSAGE SEVERITY */
DCL &SENDER *CHAR 80 /* SENDER DATA STRUCTURE */
DCL &RTNTYPE *CHAR 2 /* DIAG/COMP/INFO/REPLY */
DCL &ALROPT *CHAR 9 /* ALERT OPTION */
DCL &MSGF *CHAR 10 /* MESSAGE FILE NAME */
DCL &MSGFLIB *CHAR 10 /* AND ITS LIBRARY */
DCL &SNDMSGFLIB *CHAR 10 /* SENDER'S MESSAGE FILE LIBRARY */
RCVMSG MSGQ(qsys/qsysopr) WAIT(*MAX) RMV(*NO) KEYVAR(&KEYVAR) MSG(&MSGL1) +
MSGLEN(&MSGL1LEN) SECLVL(&MSGL2) SECLVLLEN(&MSGL2LEN) +
MSGDTA(&MSGDTA) MSGDTALEN(&MSGDTALEN) MSGID(&MSGID) SEV(&SEV) +
SENDER(&SENDER) SENDERFMT(*SHORT) RTNTYPE(&RTNTYPE) ALROPT(&ALROPT) +
MSGF(&MSGF) MSGFLIB(&MSGFLIB) SNDMSGFLIB(&SNDMSGFLIB)
ENDPGM

 

MONQSOMS1 Rpgle program

A questo punto creiamo un sorgente SQLRPGLE, copiamo e compiliamo quanto segue … in pratica il cuore del monitor è qui

Sintesi programma MONQSOMS1:

  1. Per prima cosa crea, se già non esiste, una tabella di appoggio QUSRSYS/MsgMonT che conterrà i CPF monitorati per i quali scatenare l’evento IFTTT.
  2. La prima volta che viene creata la tabella QUSRSYS/MsgMonT vengono pre-inseriti alcuni CPF di errore tipici per i quali metto un “Notify” per default … qui potete aggiungere quelli che volete oppure semplicemente riguardarla di tanto in tanto (i nuovi CPF che vengono rilevati si inserisco in automatico nella tabella con una azione “Unknown”
  3. Poi MONQSOMS1 chiama MONQSOMS2 e resta in attesa di un MSG della QSYSOPR
  4. Controlla nella tabella QUSRSYS/MsgMonT e se desiderato scatena un notififica HTTP a IFTTT (vedi procedura chk_msgid e notify_IFTTT.

Una volta compilato si può eseguire o sottomettere in Batch ad esempio nella JOBQ QSYS/QSYSNOMAX essendo un lavoro che rimane attivo in MSGW per tutto o quasi il tempo.

SBMJOB CMD(CALL PGM(MONQSOMS1)) JOB(MONQSOMS1) JOBQ(QSYS/QSYSNOMAX) JOBD(yourjobd)

Mettendo in debug il programma e lavorando sul valore di Maction possiamo scatenare un evento IFTTT con il primo messaggio che arriva in QSYSOPR …

 

Conclusione

In questo caso abbiamo inviato una notifica al nostro Iphone o Android … ma il bello di IFTTT che potremmo creare una “recipe” per accendere una luce (vedi Philips Hue Channel, Emberlight, LightWave, WeMo Lighting ecc), aprire un garage (Garageio), far partire la lavastoviglie (Samsung Washer, LG Washer ecc) o una chiamata telefonica (Phone Call) o altre mille diavolerie che l’Internet of Things di oggi e di domani porterà nelle nostre case / uffici / e indosso a noi.

 

Sorgente di MONQSOMS1 SQLRPGLE

ctl-opt dftactgrp(*no) ;
//--------------------------------------------------
// MONQSOMS1: Monitor QSYSOPR Message Queue
// and trigger an event for IFTTT app
// SBMJOB CMD(CALL PGM(MONQSOMS1)) JOB(MONQSOMS1)
// JOBQ(QSYS/QSYSNOMAX)
//--------------------------------------------------
// MONQSOMS2 CLP ... RCVMSG from Qsysopr
Dcl-pr rtvqsoms2 ExtPgm('MONQSOMS2');
KeyVar Char(4) const;
MsgL1 Char(100) const;
MsgL1Len Packed(5:0) const;
MsgL2 Char(100) const;
MsgL2Len Packed(5:0) const;
MsgDta Char(100) const;
MsgDtaLen Packed(5:0) const;
MsgId Char(7) const;
Sev Packed(2:0) const;
Sender Char(80) const;
RtnType Char(02) const;
AlrOpt Char(09) const;
MsgFile Char(10) const;
MsgFileLib Char(10) const;
MsgFileSnd Char(10) const;
End-pr;
// MsgMonT DS and Table to store CPF to Notify or Ignore
dcl-ds MsgMonT;
MMsgID char(09);
MMsgDesc char(100);
MMsgSev Packed(2:0);
MAction char(10);
MTimestamp Timestamp;
END-DS;
dcl-pr qCmdExc ExtPgm('QCMDEXC');
Cmd char(1000) options(*varsize) const ;
CmdLenn packed(15:5) const ;
END-PR;
dcl-s Timest Timestamp;
dcl-s KeyVar Char(4);
dcl-s MsgL1 Char(100);
dcl-s MsgL1Len Packed(5:0);
dcl-s MsgL2 Char(100);
dcl-s MsgL2Len Packed(5:0);
dcl-s MsgDta Char(100);
dcl-s MsgDtaLen Packed(5:0);
dcl-s MsgId Char(7);
dcl-s Sev Packed(2:0);
dcl-s Sender Char(80);
dcl-s RtnType Char(02);
dcl-s AlrOpt Char(09);
dcl-s MsgFile Char(10);
dcl-s MsgFileLib Char(10);
dcl-s MsgFileSnd Char(10);
dcl-s Cmd Char(1024);
// Change CCSID for HTTP Functions
Cmd='CHGJOB CCSID(37)';
qCmdExc(Cmd:%len(Cmd));
// Check mymsgmonitor table if not exist create it
Chk_MsgMonT();
// Cicle to monitor msg ... JOB stay in MSGW state waiting for
// QSYSOPR messages ...
dow 1=1;
// Call CLLE to RCVMSG from QSYSOPR ... (Normally wait in MSGW Status)
rtvqsoms2(KeyVar:MsgL1:MsgL1Len:MsgL2:MsgL2Len:MsgDta:MsgDtaLen:Msgid
:Sev:Sender:RtnType:AlrOpt:MsgFile:MsgFileLib:MsgFileSnd);
// Check message in Message Monitor Table ... for certain type of
// messages send an event to IFTTT service
Chk_msg(MsgId:MsgL1:MsgL2:Sev);
ENDDO;
*inlr = *on ;
//-----------------------
// chk_msg
//-----------------------
dcl-proc chk_msg;
dcl-pi chk_msg;
MsgId Char(7);
MsgL1 Char(100);
MsgL2 Char(100);
Sev Packed(2:0);
END-PI;
// Msg without MsgId ignored;
if MsgId='';
return;
ENDIF;
// Check if is a known message in Msg Monitor Table
clear MsgMonT;
exec sql
select *
into :MsgMonT
from QUsrSys.MsgMonT
where MMsgId=:MsgId;
select;
// MsgId not found ... insert a new record in
// MsgMonitorTable as Unknown message
When MMsgID=*blanks;
MMsgid=MsgId;
MMsgDesc=MsgL1;
MMsgSev=Sev;
MAction='Unknown';
MTimestamp=%timestamp;
exec sql
insert into QUsrSys.MsgMont
values(:MsgMonT);
// Case Ignore/Uknnown Message ...
When MAction='Ignore' or
Maction='Unknown';
timest=%timestamp;
exec sql
update QUsrSys.MsgMonT
set MTimestamp=:timest
where MMsgid=:MsgId;
// Case Notify MsgId
When MAction='Notify';
timest=%timestamp;
exec sql
update QUsrSys.MsgMonT
set MTimestamp=:timest
where MMsgid=:MsgId;
Notify_ifttt(MsgId:MsgL1:Sev);
ENDSL;
return;
end-proc;
//---------------------------------
// Notify_ifttt
//---------------------------------
DCL-PROC Notify_ifttt;
dcl-pi Notify_ifttt;
MsgId Char(7);
MsgL1 Char(100);
Sev Packed(2:0);
END-PI;
dcl-s IFTTT_Key Char(300);
dcl-s IFTTT_Event Char(300);
dcl-s IFTTT_Value1 Char(300);
dcl-s IFTTT_Value2 Char(300);
dcl-s IFTTT_Value3 Char(300);
dcl-s IFTTT_Url Char(300);
dcl-s IFTTT_Returnval Char(300);
// IFTTT_Key Set your key as in your IFTTT account
IFTTT_Key='YOUR_SPECIFIC_IFTTT_KEY_HERE';
// IFTTT_Event Set your event as in your IFTTT Recipe
IFTTT_Event='IBMi_Message';
// I use 3 free Maker variables to store CPFID, Description and Severity
IFTTT_Value1=MsgId;
IFTTT_Value2=MsgL1;
IFTTT_Value3=%editc(Sev:'X');
// Build URL for IFTTT Api
IFTTT_Url='https://maker.ifttt.com/trigger/'
+%trim(IFTTT_Event)
+'/with/key/'
+%trim(IFTTT_Key)
+'?value1='+%trim(IFTTT_Value1)
+'&value2='+%trim(IFTTT_Value2)
+'&value3='+%trim(IFTTT_Value3)
+'';
clear IFTTT_returnval;
exec sql
Select trim(json) into: IFTTT_Returnval
From (Values(SYSTOOLS.HTTPGETCLOB(
replace(trim(:IFTTT_Url),' ','%20'),''))) x(json);
if %subst(IFTTT_Returnval:1:15)='Congratulations';
// Ok Event triggered
else;
// Oh, something went bad
ENDIF;
END-PROC;
//---------------------------------
// Chk_MsgMonitortable
//---------------------------------
DCL-PROC Chk_MsgMonT;
// I use a MsgMonitorTable to store MSGID and
// actions ... so I can choose what to do
// with singole MSGID
exec sql
CREATE TABLE QUSRSYS/MsgMonT
(MMsgID char(09) unique,
MMsgDesc char(100),
MMsgSev dec(2, 0),
MAction char(10),
MTimestamp Timestamp
);
// First time (SQL7095) insert some MsgId to Notify ... add here yours MsgId
// or check periodically record with "Unknown" action and change
// them to "Ignore" or "Notify"
if sqlcod=7905;
// CPF0907 Problem with Memory
clear MsgMont;
mmsgid='CPF0907';
mmsgdesc='Serious storage condition may exist';
mmsgsev=80;
maction='Notify';
mtimestamp=%timestamp;
exec sql insert into QusrSys.MsgMonT values(:MsgMont);
// CPPEA03 Hardware Problems
clear MsgMont;
mmsgid='CPPEA03';
mmsgdesc='Problem with Hwardware';
mmsgsev=80;
maction='Notify';
mtimestamp=%timestamp;
exec sql insert into QusrSys.MsgMonT values(:MsgMont);
// CPI5922 Problems with tape
clear MsgMont;
mmsgid='CPI5922';
mmsgdesc='Dev tape not usable';
mmsgsev=70;
maction='Notify';
mtimestamp=%timestamp;
exec sql insert into QusrSys.MsgMonT values(:MsgMont);
// CPA0702 Problems with batch job
clear MsgMont;
mmsgid='CPA0702';
mmsgdesc='Problems with a Batch JOB';
mmsgsev=70;
maction='Notify';
mtimestamp=%timestamp;
exec sql insert into QusrSys.MsgMonT values(:MsgMont);
// RNQ1216 Open file problem
clear MsgMont;
mmsgid='RNQ1216';
mmsgdesc='Open file problem';
mmsgsev=99;
maction='Notify';
mtimestamp=%timestamp;
exec sql insert into QusrSys.MsgMonT values(:MsgMont);
ENDIF;
END-PROC;

1 COMMENT