1% MQTT pack for SWI-Prolog
    2% 2016-05-24 - olsky - initial draft 
    3% 2016-05-30 - olsky - working connect and publish
    4%
    5
    6:- module(mqtt, [
    7mqtt_connect/2,
    8mqtt_connect/3,
    9mqtt_connect/4,
   10mqtt_disconnect/1,
   11mqtt_loop/1,
   12mqtt_pub/4,
   13mqtt_pub/3,
   14mqtt_sub/3,
   15mqtt_sub/2,
   16mqtt_unsub/2,
   17mqtt_version/3,
   18pack_version/3,
   19mqtt_version/1,
   20pack_version/1
   21]).   22
   23:- load_foreign_library(foreign(mqtt)).   24
   25
   26:- multifile
   27  mqtt_hook_on_connect/2,
   28  mqtt_hook_on_disconnect/2,
   29  mqtt_hook_on_message/2,
   30  mqtt_hook_on_subscribe/2,
   31  mqtt_hook_on_publish/2,
   32  mqtt_hook_on_unsubscribe/2,
   33  mqtt_hook_on_log/2.   34  
   35:- dynamic 
   36  mqtt_connection/2.   37
   38
   39mqtt_loop(C) :-
   40 c_mqtt_loop(C).
   41
   42mqtt_version(Ma, Mi, Re) :-
   43  c_mqtt_version(Ma, Mi, Re).
   44pack_version(Ma, Mi, Re) :-
   45 c_pack_version(Ma, Mi, Re).
   46mqtt_version(Version) :-
   47  c_mqtt_version(Version).
   48pack_version(Version) :-
   49 c_pack_version(Version).
   50
   51
   52% mqtt_connect(-Connection, +Host) default port 1883
   53mqtt_connect(Connection, Host) :- 
   54  mqtt_connect(Connection, Host, 1883),
   55  true.  
   56
   57% mqtt_connect(-Connection, +Host, +Port)
   58mqtt_connect(Connection, Host, Port) :-
   59  gensym(mqtt_conn_, A),
   60  gensym(swi_mqtt_client, Cid),
   61  
   62  mqtt_connect(Connection, Host, Port, [alias(A), client_id(Cid), keepalive(10), is_async(false)]),
   63  true.
   64  
   65% mqtt_connect(-Connection, +Host, +Port, [Options])
   66% options are:  
   67% - alias(A), client_id(Cid), keepalive(10), is_async(false)
   68% callbacks:
   69% - module()
   70% - on_connect() on_disconnect()  on_log() 
   71% - on_message() on_publish() on_subscribe(), on_unsubscribe()
   72mqtt_connect(Connection, Host, Port, Options) :-
   73  nonvar(Host),
   74  nonvar(Port),
   75  (
   76    member(is_async(true), Options)
   77     -> ignore(c_create_engine)
   78     ; true
   79  ),
   80  c_mqtt_connect(Connection, Host, Port, Options),
   81  (
   82   member(alias(A), Options)
   83     -> true
   84      ;  gensym(mqtt_conn_, A)
   85  ),
   86  assert(mqtt_connection(A, Connection)),
   87  % needed? call_mqtt_connected_hook(Connection, [flow(prolog)]),
   88  true.
   89
   90
   91% close connection
   92mqtt_disconnect(Connection) :-
   93  (c_mqtt_disconnect(Connection)
   94    -> retractall(mqtt_connection(_, Connection))
   95    ; fail
   96  ),
   97  % needed? call_mqtt_disconnected_hook(Connection, [flow(prolog)]),
   98  true.
   99
  100
  101mqtt_pub(Connection, Topic, Payload) :-
  102  mqtt_pub(Connection, Topic, Payload, [retain(false), qos(0)]).
  103
  104% publish to mqtt
  105mqtt_pub(Connection, Topic, Payload, Options) :-
  106  c_mqtt_pub(Connection, Topic, Payload, Options),
  107  true.
  108
  109
  110
  111% subscribe with: 
  112% - topic pattern
  113% - qos
  114mqtt_sub(Connection, Topic, Options) :-
  115  c_mqtt_sub(Connection, Topic, Options),
  116  true.
  117mqtt_sub(Connection, Topic) :-
  118  mqtt_sub(Connection, Topic, []).
  119
  120
  121% unsubscribe from: 
  122% - topic pattern
  123mqtt_unsub(Connection, Topic) :-
  124  c_mqtt_unsub(Connection, Topic),
  125  true.
  126
  127
  128% hook dump
  129mqtt_hook_dump(Event, C, Data) :-
  130  thread_self(T), 
  131  format('% hook <~w> ~t <~w> ~t <mqtt:~w> ~t <~w>~n', [T, Event, C, Data]), 
  132  %sleep(2),
  133  true.
  134
  135% hooks:
  136
  137mqtt_hook_on_connect(C, Data)     :- mqtt_hook_dump(on_connect, C, Data).
  138mqtt_hook_on_disconnect(C, Data)  :- mqtt_hook_dump(on_disconnect, C, Data).
  139mqtt_hook_on_message(C, Data)     :- mqtt_hook_dump(on_message, C, Data).
  140mqtt_hook_on_subscribe(C, Data)   :- mqtt_hook_dump(on_subscribe, C, Data).
  141mqtt_hook_on_publish(C, Data)     :- mqtt_hook_dump(on_publish, C, Data).
  142mqtt_hook_on_unsubscribe(C, Data) :- mqtt_hook_dump(on_unsubscribe, C, Data).
  143mqtt_hook_on_log(C, Data)         :- mqtt_hook_dump(on_log, C, Data)