diff options
author | Magnus <mfeuer@jaguarlandrover.com> | 2014-08-11 14:10:55 -0700 |
---|---|---|
committer | Magnus <mfeuer@jaguarlandrover.com> | 2014-08-11 14:10:55 -0700 |
commit | b928375c535c8d239c77938dd87d63dc3ad9af75 (patch) | |
tree | 57a1b1a11f3266ab444686010b652e96c29aa01a | |
parent | 90ed8e6400d09654f0e2b7969c5bd9cb743235c4 (diff) | |
download | rvi_core-b928375c535c8d239c77938dd87d63dc3ad9af75.tar.gz |
Temp
Signed-off-by: Magnus <mfeuer@jaguarlandrover.com>
-rw-r--r-- | Makefile | 30 | ||||
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | TODO | 15 | ||||
-rw-r--r-- | hvac_demo/README.md | 75 | ||||
-rwxr-xr-x | hvac_demo/hvac_emulator.py | 59 | ||||
-rwxr-xr-x | hvac_demo/hvac_subscription_service.py | 93 | ||||
-rw-r--r-- | hvac_demo/rvi_json_rpc_server.py | 28 | ||||
-rw-r--r-- | setup_rvi_node.sh | 43 |
8 files changed, 269 insertions, 75 deletions
@@ -1,10 +1,14 @@ +# +# Makefile for the RVI node. +# +# + .PHONY: all deps compile setup clean doc setup_backend setup_device NAME=rvi -export KVDB_BACKENDS=ets +SETUP_GEN=./deps/setup/setup_gen -SETUP_GEN=$(shell ./find_setup_gen.sh) all: deps compile @@ -18,17 +22,10 @@ compile: recomp: ./rebar compile skip_deps=true -setup_device: - ERL_LIBS=$(PWD)/deps:$(ERL_LIBS):$(PWD) \ - $(SETUP_GEN) $(NAME) priv/setup_device.config setup_device - -setup_backend: - ERL_LIBS=$(PWD)/deps:$(ERL_LIBS):$(PWD) \ - $(SETUP_GEN) $(NAME) priv/setup_backend.config setup_backend target_backend: ERL_LIBS=$(PWD)/deps:$(ERL_LIBS) \ - $(SETUP_GEN) $(NAME) priv/setup_backend.config setup -pz $(PWD)/ebin \ + $(SETUP_GEN) $(NAME) priv/backend.config setup -pz $(PWD)/ebin \ -target rel_backend -vsn 0.1 target_device: @@ -36,19 +33,6 @@ target_device: $(SETUP_GEN) $(NAME) priv/setup_device.config setup -pz $(PWD)/ebin \ -target rel_device -vsn 0.1 -# -# Start the backend server -# -run_backend: setup_backend - erl -boot setup_backend/start -config setup_backend/sys - - -# -# Start the backend device. -# -run_device: setup_device - erl -boot setup_device/start -config setup_device/sys - doc: ./REBAR_DOC=1 ./rebar skip_deps=true get-deps doc @@ -1,5 +1,6 @@ # TOP LEVEL RVI PROJECT + Better documentation coming soon. Preqequisites. @@ -1,6 +1,17 @@ In doc and code, convert JSON-RPC param "parameters" to "arguments" in order to avoid confusion with JSON-RPC "params" -In doc and code, rename "target" "service" or potentially "target service" +In doc and code, rename "target" "service" or potentially "target + service" + +In HLD, update data_link_up use case (Step 10) to involve service + discovery + +In HLD, schedule, data link, and service discovery - Fix code so that + service availability is managed by service discovery only. Today + the network address of a given service (set by data_link_up calls + from data_link_device) are received by schedule, which maintains a + redundant copy of all service availability states. This should be + moved to Servide Discovery, which should forward the call to + schedule. HLD - diff --git a/hvac_demo/README.md b/hvac_demo/README.md index 01821d2..9c9be51 100644 --- a/hvac_demo/README.md +++ b/hvac_demo/README.md @@ -1,11 +1,72 @@ -The HVAC service is a test service that registers with the backend server to handle a very simple pub/sub setup. +# HVAC DEMO -Accepted commands are: -subscribe(vin, subscriber) -> Any updates to the given vin should be sent as publish command to the given subscriber (a service running on a device). -unsubscribe(vin, subscriber) -> Remove subscription conenction between subscriber and vin. +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/ + +# BACKGROUND +The remote HVAC control demo is a part of the Automotive Grade Linux +project where the Tizen IVI climate control (HVAC) screen can be +remotely controlled from a mobile device. Updates made to the IVI HVAC +screen are sent in real time to the mobile device, and vice versa. + +An initial release of the remote HVAC demo was done using the MQTT +protocol (mqtt.org). The first milestone of the RVI project will +migrate the HVAC demo to the RVI technology. + +# CONTENT +This directory contains a simple subscription service +(hvac\_subscription\_service.py) replacing the MQTT broker. The +subscription service lets the IVI and mobile devices setup +subscriptions so that they receive notifications when the HVAC values +for a specific VIN (Vehicle Identification Number) have been +updated. The service is, in effect, a standard publish/subscribe +setup. + +In order to test the RVI milestone 1 and the subscription service +without having to bring up a complete Tizen IVI and mobile device +environment, a simple emulator for these two components have been +providedin hvac_emulator.py. + +The emulator can be started in IVI or mobile device mode. Please run +./hvac_emulator.py for usage details. + +# TEST SETUP + +Two RVI nodes will be involved in the test: + +The backend node will host the subscription service (hvac\_subscription\_service.py), and will also +receive requests from the mobile device emultor (hvac_emulator.py). + +The IVI node will host the IVI emulator. + +## CREATE THE MOBILE DEVICE NODE + +From the rvi root directory, setup the mobile device node: + + ./setup_rvi_node ivi priv/setup_ivi.config + +In a similar manner, setup the IVI backend node: + + ./setup_rvi_node backend priv/setup_backend.config + +The result will be two new directories, ivi and backend, created under the rvi root directory. + +Since both rvi nodes will execute on the same machine, each node will have to specify their +own port range, which is handled through the -p + + +In antoer window, launch the backend node: + + + ./rvi_node -n backend -p 23070 + + +Launch the IVI rvi node in its own window: + + ./rvi_node -n ivi -p 23050 -b localhost:23070 -publish(vin, key, value) -> A given vin is updating a key with a new value. All subscribers to the vin will be notified. -Dependencies: -pip install jsonrpclib diff --git a/hvac_demo/hvac_emulator.py b/hvac_demo/hvac_emulator.py index a9cc863..4b42c08 100755 --- a/hvac_demo/hvac_emulator.py +++ b/hvac_demo/hvac_emulator.py @@ -1,6 +1,14 @@ #!/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 @@ -90,7 +98,6 @@ import threading # SUBSCRIPTION_SERVICE_BASE='jlr.com/backend/subscription_service' SUBSCRIBE_SERVICE=SUBSCRIPTION_SERVICE_BASE+'/subscribe' -UNSUBSCRIBE_SERVICE=SUBSCRIPTION_SERVICE_BASE+'/unsubscribe' PUBLISH_SERVICE=SUBSCRIPTION_SERVICE_BASE+'/publish' # @@ -100,7 +107,7 @@ PUBLISH_SERVICE=SUBSCRIPTION_SERVICE_BASE+'/publish' # def publish(vin, key, value): print "Publish invoked!" - print "vin:", viny + print "vin:", vin print "key:", key print "value:", value return ['ok'] @@ -115,6 +122,9 @@ def usage(): 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) @@ -127,7 +137,7 @@ def usage(): # emulator_service_host = 'localhost' emulator_service_port = random.randint(20001, 59999) - +emulator_service_url = 'http://'+emulator_service_host + ':' + str(emulator_service_port) @@ -152,10 +162,24 @@ if len(sys.argv) == 5: # 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 @@ -173,21 +197,20 @@ elif len(sys.argv) == 3: # Setup an outbound JSON-RPC connection to the RVI Service Edeg. rvi_server = jsonrpclib.Server(rvi_url) - # Register our HVAC IVI/mobile emulator service with the RVI Service Edge, + # 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 = - 'http://'+emulator_service_host + ':' + str(emulator_service_port)) + 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 - print "res = ", res - svc_name = res['service'] + full_emulator_service_name = res['service'] - [ t1, t2, vin, t3, t4] = svc_name.split('/') + [ 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 @@ -215,7 +238,7 @@ rvi_server.message(calling_service = emulator_service_name, target = SUBSCRIBE_SERVICE, timeout = 0, parameters = [{ u'vin': sub_vin, - u'subscribing_service': emulator_service_name}]) + 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 @@ -223,15 +246,25 @@ 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 - [k, v] = raw_input('Enter <key> <val>: ').split(' ') + 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, + rvi_server.message(calling_service= emulator_service_name, target = PUBLISH_SERVICE, timeout = 0, parameters = [{ u'vin': pub_vin, u'key': k, - u'val': v}]) + u'value': v}]) print('Key {} set to {} for vin{}'. format(k, v, vin)) diff --git a/hvac_demo/hvac_subscription_service.py b/hvac_demo/hvac_subscription_service.py index 88c8435..27c9d05 100755 --- a/hvac_demo/hvac_subscription_service.py +++ b/hvac_demo/hvac_subscription_service.py @@ -1,4 +1,60 @@ #!/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/ +# + +# +# This is an extremely simple subscription service that connects to +# a central backend RVI node. The node is well known by all +# other RVI nodes in a network, who has the backedn node configured +# as a "static" node. See priv/setup_device.config for an example. +# +# The subscription service will register the following services +# with the backend RVI node: +# +# /subscription_service/subscribe +# (Full name: jlr.com/backend/subscription_service/subscribe) +# Parameters: +# vin - The VIN number for which updates are subscribed to. +# subscribing_service - The service to send a message to when +# the given vin is updated. +# +# Adds the given service to the list of subscribers to notify +# +# When a message is recieved by the /subscribing_service/publish +# service, all subscribers who have specified a vin +# matching that provided with the publish message will have +# the message forwarded to them. +# +# /subscription_service/unsubscribe +# (Full name: jlr.com/backend/subscription_service/unsubscribe) +# Parameters: +# vin - The VIN number from which the service unsubscribes. +# subscribing_service - The service that unsubscribes., +# +# Removes a service, previously subscribing to the service through +# a subscribe command, from the given vin. Future updates +# to the vin will not be forwarded to the given service. +# +# /subscription_service/publish +# (Full name: jlr.com/backend/subscription_service/publish) +# Parameters: +# vin - The VIN number from which the service unsubscribes. +# key - The key that has an updated value +# value - The new value assigned to key +# +# Distributes the key/value pair to all services that have previosuly +# subscribed to updates for the given vin. +# +# For RVI Milestone 1, the mobile and Tizen IVI UI remains to be +# integrated with the RVI system itself. Meanwhile, hvac_emulator.py +# is provded as a simple tester that can emulate either an IVI or +# a mobile device. +# from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer import jsonrpclib @@ -15,7 +71,7 @@ HVAC_SERVER=('localhost', 8901) # # Thus: # { '1234': [ 'jlr.com/vin/5555/hvac_update_ui', 'jlr.com/vin/4711/hvac_update_ui'] -vin_subs = [] +vin_subs = {} def subscribe(vin, subscribing_service): print "Subscribe" @@ -23,13 +79,14 @@ def subscribe(vin, subscribing_service): print "subscribing_service:", subscribing_service # Delete any existing service with the same name - try: - vin_subs[vin].remove(subscribing_service) - except Err: - pass - # Add the subscribing service - vin_subs[vin].append(subscribing_service) + if not vin in vin_subs: + vin_subs[vin] = [subscribing_service] + else: + if vin_subs[vin].count(subscribing_service) == 0: + vin_subs[vin].append(subscribing_service) + + print "Result: ",vin_subs return ['ok'] @@ -39,10 +96,9 @@ def unsubscribe(vin, subscribing_service): print "subscribing_service:", subscribing_service # Delete any existing service with the same name - try: + + if vin in vin_subs and vin_subs[vin].count(subscribing_service) > 0: vin_subs[vin].remove(subscribing_service) - except Err: - pass return ['ok'] @@ -52,28 +108,29 @@ def publish(vin, key, value): print "key:", key print "value:", value - # Delete any existing service with the same name + # Distribute try: subs = vin_subs[vin] except Err: print "No subscribers for vin:", vin return ['ok'] + print "subs:", subs for sub in subs: print "Sending publish to", sub rvi_server.message(calling_service = '/hvac/publish', target = sub, timeout = 0, - parameters = [{ u'key': key}, {u'value': value }]) + parameters = [{ u'vin': vin, u'key': key}, {u'value': value }]) # Setup self's server that we will receive incoming calls from service edge on. hvac_server = RVIJSONRPCServer(HVAC_SERVER) # hvac_server = SimpleJSONRPCServer(HVAC_SERVER) -hvac_server.register_function(subscribe, '/hvac/subscriber_service/subscribe') -hvac_server.register_function(unsubscribe, '/hvac/subscriber_service/unsubscribe') -hvac_server.register_function(publish, '/hvac/subscriber_service/publish') +hvac_server.register_function(subscribe, '/subscription_service/subscribe') +hvac_server.register_function(unsubscribe, '/subscription_service/unsubscribe') +hvac_server.register_function(publish, '/subscription_service/publish') # Register our services with the service edge and have @@ -83,17 +140,17 @@ rvi_server = jsonrpclib.Server(RVI_SERVICE_EDGE) res = rvi_server.register_service(service = '/subscription_service/subscribe', network_address = 'http://localhost:8901') -print "Registered service /subscription_service/subscribe as", res['service'] +print "Registered service", res['service'] res = rvi_server.register_service(service = '/subscription_service/unsubscribe', network_address = 'http://localhost:8901') -print "Registered service /subscription_service/unsubscribe as", res['service'] +print "Registered service", res['service'] res = rvi_server.register_service(service = '/subscription_service/publish', network_address = 'http://localhost:8901') -print "Registered service /subscription_service/publish as", res['service'] +print "Registered service", res['service'] hvac_server.serve_forever() diff --git a/hvac_demo/rvi_json_rpc_server.py b/hvac_demo/rvi_json_rpc_server.py index 7235756..e29fbb4 100644 --- a/hvac_demo/rvi_json_rpc_server.py +++ b/hvac_demo/rvi_json_rpc_server.py @@ -1,3 +1,10 @@ +# +# 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/ +# from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer import jsonrpclib @@ -5,29 +12,26 @@ class RVIJSONRPCServer(SimpleJSONRPCServer): # Check if method is 'message', if so dispatch on # name 'target' instead. def _dispatch(self, method, params): - print "dispatch:", params + # print "dispatch:", params if method == 'message': - print "Will dispatch message to: " + params['target'] + # print "Will dispatch message to: " + params['target'] dict_param = {} # Extract the 'parameters' element from the top level JSON-RPC # 'param'. # Convert 'parameters' from [{'vin': 1234}, {hello: 'world'}] to # a regular dictionary: {'vin': 1234, hello: 'world'} - print params['parameters'] + # print "Parameters:", params['parameters'] msg_params = params['parameters'] for i in range(0, len(msg_params)): - print "params ", msg_params[i].keys()[0], " = ", msg_params[i].values()[0] - dict_param[msg_params[i].keys()[0]] = msg_params[i].values()[0] + for j in range(0, len(msg_params[i].keys())): + # print "params", msg_params[i].keys()[j], "=", msg_params[i].values()[j] + dict_param[msg_params[i].keys()[j]] = msg_params[i].values()[j] - print "DICT: ", dict_param + # print "Parameter disctionary: ", dict_param + # print # Ship the processed dispatch info upward. return SimpleJSONRPCServer._dispatch(self, params['target'], dict_param) - print "Method:", method - for x in params: - print "params ", x, " = ",params[x] - return SimpleJSONRPCServer._dispatch(self,message, params) - - print "---" + return SimpleJSONRPCServer._dispatch(self,message, params) diff --git a/setup_rvi_node.sh b/setup_rvi_node.sh new file mode 100644 index 0000000..8cefbd1 --- /dev/null +++ b/setup_rvi_node.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# +# 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/ +# + +# +# Setup an RVI release with a configuration file. +# +# This script will setup a directory with with the same name +# as the release name. The script uses Ulf Wiger's setup application +# (github.com/Feuerlabs/setup) to generate the release. +# +# Once setup, the RVI node can be started with ./rvi_node <release_na,e? +# +# Please note that the generated release will depend on the built +# +# In order to create a standalone release, use create_rvi_release.sh +# +SETUP_GEN=./deps/setup/setup_gen # Ulf's kitchen sink setup utility + +if [ "$#" != "2" ] +then + echo "Usage: $0 <release_name> <config_file>" + echo "Will create a subdirectory named <release_name> which contains" + echo "all configuration and boot files necessary to bring up an rvi node." + echo + echo "Launch the node with ./rvi_node <release_name>" + echo + echo "See priv/sample.config for example configuration file" + echo + exit 1 +fi + +export ERL_LIBS=$PWD/deps:$ERL_LIBS:$PWD + +$SETUP_GEN $1 $2 $1 + +echo "RVI Node $1 has been setup. Launch with ./rvi_node $1" +exit 0 |