summaryrefslogtreecommitdiff
path: root/hvac_demo/hvac_emulator.py
blob: 4b42c08281b209bc24183060545e40981a55f2f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
#!/usr/bin/python

#
# Copyright (C) 2014, Jaguar Land Rover
#
# This program is licensed under the terms and conditions of the
# Mozilla Public License, version 2.0.  The full text of the 
# Mozilla Public License is at https://www.mozilla.org/MPL/2.0/
#

#
# Emulate a mobile device or an IVI.
#
#  This emulator connects to an RVI Service Edge as a service and
#  takes on one of two roles:
#
#  1) mobile device
#     In this mode the emulator connects to the Service Edge of the
#     backend server (since P2P will be supported in RVI Project
#     Milestone 2), and subscribes to HVAC updates (temp, fan speed,
#     etc) updates from an IVI with a given VIN. The emulator can also
#     update HVAC values, simulating HVAC GUI input on the phone
#     screen, and send it off to the (backend server) Service Edge for
#     further distribution to the targeted IVI.
#
#  2) IVI 
#     In this mode, the emulator connects to the Service Edge of a
#     vehicle (device) and subscribes to updates from one or more
#     mobile devices. Local updates, simulating GUI input on the
#     HVAC screen, can be entered at the command line and will be
#     distributed to the phone(s) subscribing to updates from
#     the IVI.
#
#  
#  In both modes, the emulator sends its updated HVAC values to the
#  service jlr.com/backend/hvac/subscription_service/publish. This
#  service will look up VIN targeted by the update and send out the
#  same data to all services that are subscribing to that VIN.
#  
#  In mobile device mode, the emulator will subscribe to updated
#  values published to to the VIN value "ivi_[vin]" where vin is the
#  VIN number of the IVI.  When a emulator, still in mobile device
#  mode, sends out an updated value (entered in the python console),
#  it will publish the value using the vin "mobile_[vin]"
#
#  Converesely, an emulator in IVI mode will sbuscribe to
#  "mobile_[vin]", and publish to "ivi_[vin]".
#
#  This setup allows the mobile device emulator to receive updates
#  entered on the IVI HVAC screen (sent out by the IVI to
#  "ivi_[vin]"), while the IVI emulator receives updates entered on
#  the mobile device screen (sent out by the mobile device to
#  "mobile_[vin]".
#
#  When the emulator connects in IVI mode to a device RVI node, the
#  node's configured service prefix (see priv/setup_device.config,
#  node_service_prefix) will have the VIN number as a part of the
#  prefix. The emulator will thus register its service as /hvac/publish,
#  which, prefixed with the node service prefix, gives it a complete name
#  of jlr.com/vin/[vin]/hvac/publish.
#
#  In mobile device mode, the emulator connects to the backend RVI node, which
#  has a service prefix of jlr.com/backend. In this mode, the emulator
#  will register with a phone number as a part of its service name, where
#  the phone number is specified as a command line argument to the
#  emulator.
#
#  Since the backend RVI node has a service prefix of jlr.com/backend
#  (see priv/setup_backend.config), the mobile device emulator will
#  have a complete service name of:
#  jlr.com/backend/mobile/[phone_number]/hvac/publish
#
#  [phone_number] is given at the command line.
#
#
# Usage:
#
# python hvac_emulator.py <rvi_url> [mobile <phone_number> | ivi]
#
# mob
# The rvi_url is the local URL of the RVI Service Edge. 
# See 
#
# Example:
#  python hvac_emulator.pyh mobile 9491231234 http://127.0.0.1:8811
#
#  python hvac_emulator.pyh ivi saw222992212 http://127.0.0.1:8800
#
import sys
from rvi_json_rpc_server import RVIJSONRPCServer
import jsonrpclib
import random
import threading

# The subscriber service (MQTT server equivalent), that 
# manages subscriptions and distributes received publish commands to
# the relevant subscribers.
#
SUBSCRIPTION_SERVICE_BASE='jlr.com/backend/subscription_service'
SUBSCRIBE_SERVICE=SUBSCRIPTION_SERVICE_BASE+'/subscribe'
PUBLISH_SERVICE=SUBSCRIPTION_SERVICE_BASE+'/publish'

#
# Publish command is invoked by the 
# subscriber server above when it receives a publish command
# from a VIN that this emulator subscribes to.
#
def publish(vin, key, value):
    print "Publish invoked!"
    print "vin:", vin 
    print "key:", key 
    print "value:", value 
    return ['ok']

def usage():
    print "Usage:", sys.argv[0], "<rvi_url> mobile <phone_number> <vin> | ivi"
    print "  ivi                           Emulate an IVI."
    print "  mobile <phone_number> <vin>   Emulate a mobile device with number given in"
    print "                                <phone_number> number, communicating with <vin>"
    print "  <rvi_url>                     URL of RVI Service Edge on local host"
    print
    print "The RVI Service Edge URL can be found in"
    print "priv/setup_[backend,device].config as"
    print "env -> rvi -> components -> service_edge -> url"
    print
    print "The RVI Service Edge URL can can also be specified"
    print "on the command line of the rvi_node.sh script."
    sys.exit(255)


# Setup self's server that we will receive incoming calls from service edge on.

#
# Setup a localhost URL, using a random port, that we will listen to
# incoming JSON-RPC publish calls on, delivered by our RVI service
# edge (specified by rvi_url).
#
emulator_service_host = 'localhost'
emulator_service_port = random.randint(20001, 59999)
emulator_service_url = 'http://'+emulator_service_host + ':' + str(emulator_service_port)




# 
# Check that we have the correct arguments
#
if len(sys.argv) == 5:
    [ progname, rvi_url, mode, phone_number, vin ] = sys.argv    
    if mode != 'mobile':
        print 
        print "Second argument, when three parameters are specified,  must "
        print "be 'mobile', not", mode, "."
        print
        usage()

    # We are in mobile device mode. Setup the vin numbers for publish
    pub_vin = "mobile_"+vin
    sub_vin = "ivi_"+vin

    # Setup the service name we will register with.
    # The complete service name will be: jlr.com/backend/mobile/<phone_nr>/hvac/publish
    emulator_service_name = '/mobile/'+phone_number+'/hvac/publish'


    # Setup an outbound JSON-RPC connection to the RVI Service Edeg.
    rvi_server = jsonrpclib.Server(rvi_url)

    # Register our HVAC mobile emulator service with the RVI Service Edge,
    # allowing the RVI to forward requests to the service name to the
    # given network addresss (URL):
    print "Emulator service URL", emulator_service_url
    res = rvi_server.register_service(service = emulator_service_name, 
                                      network_address = emulator_service_url)

    full_emulator_service_name = res['service']

    print "Will run in mobile device mode."
    print "Backend server node URL:  ", rvi_url
    print "Phone Number:             ", phone_number
    print "VIN:                      ", vin
    print "Full Service Name:        ", full_emulator_service_name

elif len(sys.argv) == 3:
    [ progname, rvi_url, mode ] = sys.argv    
    if mode != 'ivi':
        print 
        print "Second argument, when two are specified,  must "
        print "be 'ivi', not", mode, "."
        print
        usage()

    # setup the service name we will register with
    # The complete service name will be: jlr.com/vin/<vin>/hvac/publish
    emulator_service_name = '/hvac/publish'

    # Setup an outbound JSON-RPC connection to the RVI Service Edeg.
    rvi_server = jsonrpclib.Server(rvi_url)

    # Register our HVAC IVI emulator service with the RVI Service Edge,
    # allowing the RVI to forward requests to the service name to the
    # given network addresss (URL):

    res = rvi_server.register_service(service = emulator_service_name, 
                                      network_address = emulator_service_url)

    # The returned full service name contains the VIN number that we want:
    #  jlr.com/vin/<vin>/hvac/publish
    # We need to dig out the <vin> bit

    full_emulator_service_name = res['service']

    [ t1, t2, vin, t3, t4] = full_emulator_service_name.split('/')
    print "vin:", vin,
    
    # We are in mobile device mode. Setup the vin numbers for publish
    pub_vin = "ivi_"+vin
    sub_vin = "mobile_"+vin

    print "Will run in IVI mode."
    print "Device node URL:  ", rvi_url
    print "VIN:              ", vin
else:
    usage()


# Regsiter self's service with the backend server RVI node
# See rvi_json_rpc_server.py._dispatch() for details on how
# ncoming JSON-RPC requests are mapped to local funcitons.
#
emulator_service = RVIJSONRPCServer(((emulator_service_host, emulator_service_port)))
emulator_service.register_function(publish, emulator_service_name)

# Send of a subscribe to the subscription service running on the
# backend. See hvac_subscription_service.py.subscribe() for details.

rvi_server.message(calling_service = emulator_service_name,
                   target = SUBSCRIBE_SERVICE,
                   timeout = 0,
                   parameters = [{ u'vin': sub_vin, 
                                  u'subscribing_service': full_emulator_service_name}])

# Create a thread to handle incoming stuff so that we can do input
# in order to get new values
thr = threading.Thread(target=emulator_service.serve_forever)
thr.start()

while True:
    line = raw_input('Enter <key> <val> or "q" for quit: ')
    if line == 'q':
        emulator_service.shutdown()
        sys.exit(0)

    # Read a line and split it into a key val pair
    lst = line.split(' ')
    if len(lst) != 2:
        print "Nope", len(lst), lst
        continue
    
    [k, v] = line.split(' ')
    
    # Send out update to the subscriber
    rvi_server.message(calling_service= emulator_service_name,
                       target = PUBLISH_SERVICE,
                       timeout = 0,
                       parameters = [{ u'vin': pub_vin, 
                                      u'key': k, 
                                      u'value': v}])

    print('Key {} set to {} for vin{}'. format(k, v, vin))