├── README.md ├── api-caller ├── README.md ├── __pycache__ │ ├── caller.cpython-36.pyc │ ├── caller.cpython-38.pyc │ ├── organizer.cpython-36.pyc │ ├── organizer.cpython-38.pyc │ ├── orginizer.cpython-36.pyc │ └── orginizer.cpython-38.pyc ├── caller.py ├── communicator.py └── organizer.py ├── dataVisualization ├── README.md └── visualiser │ ├── README.md │ ├── libwebsocckets-1.7.8.html │ ├── npm-debug.log │ ├── resources │ └── Location_dot_yellow.png │ └── src │ ├── Queue.js │ ├── map.css │ ├── map.html │ ├── map.js │ ├── pom.xml │ └── websockettest.html └── generator ├── GUI.py ├── README.md ├── database.py ├── publisher.py └── subscriber.py /README.md: -------------------------------------------------------------------------------- 1 | ⛤ Traffic Visualizer ⛤ 2 | 3 | A university project designed by: 4 | 5 | Hannah Maltkvist
6 | Nafen Haj Ahmad
7 | Hassan Mualla
8 | Shab Pompeiano 9 | 10 | 11 | 12 | Stanko Janković, Adelric Wong, 13 | 14 | Features: 15 | * Easy to use Traffic Visualizer Interface 16 | * View walking routes, bus routes and bottlenecks in the Gothenburg area 17 | * Navigation control: Zoom in/out on map, switch map view 18 | * pasue and unpause lines showing up in the map 19 | 20 | 21 | Purpose: 22 | * Enables Västtrafik staff to: 23 | * ⭒Determine routes that are frequently used and routes that do not exist 24 | * ⭒View insights on bus stop placements 25 | * Enables City Planner to: 26 | * ⭒View road usage and frequency of use 27 | * ⭒View route statistics and crowd levels 28 | 29 | 30 | 31 | 32 | 33 | Technologies Involved: 34 | * HTML 35 | * CSS 36 | * Javascript 37 | * Python 38 | * MQTT 39 | 40 | 41 | References: 42 | * Show and hide layers:https://docs.mapbox.com/mapbox-gl-js/example/toggle-layers/ 43 | * Display a popup on hover: https://docs.mapbox.com/mapbox-gl-js/example/popup-on-hover/ 44 | * Create interactive hover effects with Mapbox GL JS: https://docs.mapbox.com/help/tutorials/create-interactive-hover-effects-with-mapbox-gl-js/ 45 | * Learn about websockets: http://www.steves-internet-guide.com/using-javascript-mqtt-client-websockets/ 46 | 47 | 48 | The Visualiser works by taking the information relayed from the broker once it 49 | has gone through the next component, which filters that data. The visualiser presents that data by a line on 50 | the map. From here you can see how the density of requests to and from certain 51 | areas builds over time. 52 | 53 | # How to run: 54 | 55 | Once you've cloned the repo: 56 | 1. Navigate into the api-caller folder and run "python3 communicator.py" 57 | 2. In a new window, navigate into the generator folder and run "python3 publisher.py" 58 | 3. Open map.HTML in your browser window 59 | 4. Watch the lines start to show up across the screen! 60 | -------------------------------------------------------------------------------- /api-caller/README.md: -------------------------------------------------------------------------------- 1 | **INTRODUCTION** 2 | 3 | This project holds a component called ResRobot Caller. It contains three subcomponents, Communicator, Caller, and organizer. 4 | 5 | **COMMUNICATOR** 6 | 7 | The Communicator's main responsibility is to subscribe to the data published by the emitter. 8 | The communicator also checks if the data recieved is valid in the context of our system and if it is, it forwards that data to 9 | calller and organizer in a thread. 10 | Using threads in this stage applies asynchronuousy. Thus, improving preformance. It is an appropriate place to introduce threads as 11 | the methods in the caller and organizer wait for external event 12 | Resources: 13 | https://realpython.com/intro-to-python-threading/ 14 | 15 | http://www.steves-internet-guide.com/into-mqtt-python-client/ 16 | 17 | Required Libraries: 18 | * import requests 19 | * import paho.mqtt.client as paho 20 | * import json 21 | * import isodate 22 | * import threading 23 | * import caller 24 | * import organizer 25 | * import time 26 | * import datetime 27 | 28 | 29 | **CALLER** 30 | 31 | The Caller's main responsibility is to call api ResRobot. Since there is a limit for the number of requests per minute, 32 | the method is decorated by a circuit breaker, that raises an exception in the thread in case there is a failure response from the api 33 | the failure response is 400. The raised exception, stops the thread from proceeding to the Organizer. 34 | 35 | Resources: 36 | https://truveris.github.io/articles/pycon-2016/ 37 | 38 | 39 | Required Libraries: 40 | * import requests 41 | * import json 42 | * import isodate 43 | * import pybreaker 44 | 45 | **ORGANIZER** 46 | 47 | The main Organizer's main responsibility is to iterate through the response from the api, extract the shortest trip from the 48 | list of responses. When the response is 500, it means that there are no trips/bus stops that connect the coordinates published 49 | from the emitter. The method send_response method fowards a package that the Commuincator publishes it to the Visualizer. 50 | 51 | Required Libraries: 52 | * import isodate 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /api-caller/__pycache__/caller.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malties/dataVisualization/a860973e6064f43625dbf2c83c04f8ba574d3761/api-caller/__pycache__/caller.cpython-36.pyc -------------------------------------------------------------------------------- /api-caller/__pycache__/caller.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malties/dataVisualization/a860973e6064f43625dbf2c83c04f8ba574d3761/api-caller/__pycache__/caller.cpython-38.pyc -------------------------------------------------------------------------------- /api-caller/__pycache__/organizer.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malties/dataVisualization/a860973e6064f43625dbf2c83c04f8ba574d3761/api-caller/__pycache__/organizer.cpython-36.pyc -------------------------------------------------------------------------------- /api-caller/__pycache__/organizer.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malties/dataVisualization/a860973e6064f43625dbf2c83c04f8ba574d3761/api-caller/__pycache__/organizer.cpython-38.pyc -------------------------------------------------------------------------------- /api-caller/__pycache__/orginizer.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malties/dataVisualization/a860973e6064f43625dbf2c83c04f8ba574d3761/api-caller/__pycache__/orginizer.cpython-36.pyc -------------------------------------------------------------------------------- /api-caller/__pycache__/orginizer.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malties/dataVisualization/a860973e6064f43625dbf2c83c04f8ba574d3761/api-caller/__pycache__/orginizer.cpython-38.pyc -------------------------------------------------------------------------------- /api-caller/caller.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import isodate 4 | import pybreaker 5 | 6 | 7 | #the breaker sets the parameters for which the circuit breaker follows 8 | #two consecutive fails and the circuit breaker opens 9 | #it waits for 15 seconds until it closes again 10 | breaker = pybreaker.CircuitBreaker(fail_max=2, reset_timeout=15) 11 | 12 | 13 | #decorate this method with circuit breaker 14 | @breaker 15 | def call(x): 16 | 17 | origin= (x['origin']) 18 | requestId=(x['requestId']) 19 | originLat= (origin['latitude']) 20 | originLong= (origin['longitude']) 21 | destination=(x['destination']) 22 | destinationLat= (destination['latitude']) 23 | destinationLong= (destination['longitude']) 24 | 25 | timeOfDeparture= (x['timeOfDeparture']) 26 | 27 | time= timeOfDeparture.split(" ") 28 | 29 | date= time[0] 30 | departureTime= time[1] 31 | 32 | 33 | parameters= { 34 | "originCoordLat":originLat, 35 | "originCoordLong":originLong, 36 | "destCoordLat":destinationLat, 37 | "destCoordLong":destinationLong, 38 | "date": date, 39 | "time": departureTime, 40 | "format": "json" 41 | } 42 | 43 | url = "https://api.resrobot.se/v2/trip?key=343406ee-99cc-45f9-b07c-c4d1a61a9107" 44 | 45 | 46 | response = requests.get(url, params=parameters, timeout=3) 47 | print(response.status_code) 48 | if(response.status_code==400): #when error is 400, circuit breaker opens 49 | raise pybreaker.CircuitBreakerError 50 | 51 | 52 | print("HERE") 53 | 54 | 55 | return response, parameters, requestId 56 | -------------------------------------------------------------------------------- /api-caller/communicator.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import paho.mqtt.client as paho 3 | import json 4 | import isodate 5 | import threading 6 | import caller 7 | import organizer 8 | import time 9 | import datetime 10 | 11 | 12 | threads=[] 13 | 14 | 15 | 16 | broker = "test.mosquitto.org" 17 | port = 1883 18 | 19 | 20 | def on_connect(client, userdata, flags, rc): 21 | print("Connected with result code "+str(rc)) 22 | client.subscribe("external") 23 | 24 | def on_message(client, userdata, msg): 25 | time.sleep(1) 26 | print("Receiving message") 27 | message = msg.payload.decode() 28 | 29 | x= json.loads(message) # recieve the generated information from the generator 30 | 31 | orgLat= (x['origin']['latitude']) 32 | orgLong= (x['origin']['longitude']) 33 | desLat= (x['destination']['latitude']) 34 | desLong= (x['destination']['longitude']) 35 | 36 | 37 | try: #testing if value are of correct type 38 | originlat= float(orgLat) #checking if orgLat is actually a feasible number 39 | originLong= float(orgLong) 40 | destinationLat= float(desLat) 41 | destinationlong=float(desLong) 42 | except ValueError: 43 | print("the values recieved from the generator are not valid") 44 | 45 | else: 46 | #checking if the coordinates recieved are within the Gothenburg Area 47 | if not 57.610 <= float(orgLat) <= 57.810 or not 11.723 <= float(orgLong) <= 12.157: 48 | #checkng if the coordinate values are within Gothenburg 49 | print("coordinates of origin are outside GB") 50 | elif not 57.610 <= float(desLat) <= 57.810 or not 11.723 <= float(desLong) <= 12.157: 51 | print("coordinates of destination are outside GB") 52 | else: 53 | 54 | thread= threading.Thread(target=on_thread, args=(x,)) 55 | thread.start() 56 | threads.append(thread) 57 | 58 | 59 | def on_thread(x): 60 | result=caller.call(x) # send coordinates to API 61 | y=organizer.send_response(result) # handle the response back from the API 62 | 63 | client.publish("caller/points", json.dumps(y)) #publish the response to the visualiser 64 | 65 | 66 | client = paho.Client() 67 | client.connect(broker,port,60) 68 | client.on_connect = on_connect 69 | client.on_message = on_message 70 | 71 | client.loop_forever() 72 | -------------------------------------------------------------------------------- /api-caller/organizer.py: -------------------------------------------------------------------------------- 1 | import isodate 2 | 3 | 4 | def send_response(response): 5 | result= response[0] 6 | parameters= response[1] 7 | requestId= response[2] 8 | stringID= str(requestId) 9 | 10 | showInJSON= result.json() 11 | 12 | new_payload = [] 13 | temp = 0 14 | 15 | # in case there is no bus stops/ trips that satisfy the coordinates and time 16 | if result.status_code== 500: 17 | print("unacceptable coordinates") 18 | 19 | new_payload=[] 20 | 21 | id= stringID 22 | originLat= parameters['originCoordLat'] 23 | originLong= parameters['originCoordLong'] 24 | destLat= parameters['destCoordLat'] 25 | destLong= parameters['destCoordLong'] 26 | date= parameters['date'] 27 | time= parameters['time'] 28 | print(originLat) 29 | print(id) 30 | 31 | weakOrigin={'lat': originLat, 'lng': originLong, 'time':time} 32 | weakDest= {'lat':destLat, 'lng': destLong} 33 | 34 | 35 | 36 | new_package1= {'Status': "failed",'id':id,'Origin': weakOrigin, 'Destination': weakDest} 37 | 38 | new_payload.append(new_package1) 39 | 40 | 41 | else: 42 | 43 | trips= showInJSON['Trip'] 44 | durations= [] 45 | for trip in trips: 46 | trip_duration= trip['duration'] 47 | yourdate= isodate.parse_duration(trip_duration) 48 | durations.append(yourdate) 49 | 50 | indix= durations.index(min(durations)) 51 | chosenTrip= trips[indix] 52 | interested = chosenTrip['LegList']['Leg'] 53 | 54 | 55 | # Creating new package that will be sent to the visualizer 56 | # The values get extracted from the fastest of the routes received from the API 57 | 58 | for i in range(0,len(interested)): 59 | print("beggining of loop") 60 | 61 | 62 | id = stringID + "." + str(temp) 63 | name_origin = interested[i]['Origin']['name'] 64 | type_origin = interested[i]['Origin']['type'] 65 | lat_origin = interested[i]['Origin']['lat'] 66 | lng_origin = interested[i]['Origin']['lon'] 67 | time_origin= interested[i]['Origin']['time'] 68 | 69 | 70 | 71 | new_origin = { 'name': name_origin, 'type': type_origin, 'lat': lat_origin, 'lng': lng_origin, 'time': time_origin } 72 | 73 | name_destination = interested[i]['Destination']['name'] 74 | type_destination = interested[i]['Destination']['type'] 75 | lat_destination = interested[i]['Destination']['lat'] 76 | lng_destination = interested[i]['Destination']['lon'] 77 | time_destination= interested[i]['Destination']['time'] 78 | 79 | new_destination = { 'name': name_destination, 'type': type_destination, 'lat': lat_destination, 'lng': lng_destination, 'time': time_destination } 80 | 81 | new_package = { 'Status':'success','id': id, 'Origin': new_origin, 'Destination': new_destination} 82 | 83 | 84 | 85 | new_payload.append(new_package) 86 | temp += 1 87 | 88 | 89 | 90 | return new_payload 91 | -------------------------------------------------------------------------------- /dataVisualization/README.md: -------------------------------------------------------------------------------- 1 | # wip 2 | -------------------------------------------------------------------------------- /dataVisualization/visualiser/README.md: -------------------------------------------------------------------------------- 1 | ⛤ Traffic Visualizer ⛤ 2 | A university project designed by Nafen Haj Ahmad, Shab Pompeiano, Stanko Janković, Adelric Wong, Hassan Mualla, and Hannah Maltkvist. 3 | 4 | Features: 5 | * Easy to use Traffic Visualizer Interface 6 | * View walking routes, bus routes and bottlenecks in the Gothenburg area 7 | * Navigation control: Zoom in/out on map, switch map view 8 | * paue and unpause lines showing up in the map 9 | 10 | 11 | Purpose: 12 | * Enables Västtrafik staff: 13 | * ⭒Determine routes that are frequently used and routes that do not exist 14 | * ⭒View insights on bus stop placements 15 | * Enables City Planner: 16 | * ⭒View road usage and frequency of use 17 | * ⭒View route statistics and crowd levels 18 | 19 | 20 | Technologies Involved: 21 | * HTML 22 | * CSS 23 | * Javascript 24 | * Python 25 | * MQTT 26 | 27 | 28 | References: 29 | * Show and hide layers:https://docs.mapbox.com/mapbox-gl-js/example/toggle-layers/ 30 | * Display a popup on hover: https://docs.mapbox.com/mapbox-gl-js/example/popup-on-hover/ 31 | * Create interactive hover effects with Mapbox GL JS: https://docs.mapbox.com/help/tutorials/create-interactive-hover-effects-with-mapbox-gl-js/ 32 | * Learn about websockets: http://www.steves-internet-guide.com/using-javascript-mqtt-client-websockets/ 33 | 34 | 35 | The Visualiser works by taking the information relayed from the broker once it 36 | has gone through the next component, which filters that data. The visualiser presents that data by a line on 37 | the map. From here you can see how the density of requests to and from certain 38 | areas builds over time. -------------------------------------------------------------------------------- /dataVisualization/visualiser/libwebsocckets-1.7.8.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | LWS git 18 | 19 | 20 | 21 |
22 | 23 | 24 | 26 | 27 | 34 | 35 |
25 |   28 | 29 | 30 | 31 | 32 | 33 |
Project homepageMailing List Warmcat.com API Docs Github Mirror 
36 |
37 | 38 | 39 |
40 | 41 | 42 |
43 | {"schema":"libjg2-1", 44 | "vpath":"/git/", 45 | "avatar":"/git/avatar/", 46 | "alang":"", 47 | "gen_ut":1575217508, 48 | "reponame":"libwebsockets", 49 | "desc":"libwebsockets lightweight C networking library", 50 | "owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://libwebsockets.org/repo/libwebsockets", 51 | "f":3, 52 | "items": [ 53 | { "schema":"libjg2-1", 54 | "oid":{ "oid": "bca993f7ed08e27083ea76311e5c717363a2760c", "alias": [ "refs/heads/master"]},"tree": [ 55 | { "name": "READMEs","mode": "16384", "size":0}, 56 | { "name": "cmake","mode": "16384", "size":0}, 57 | { "name": "contrib","mode": "16384", "size":0}, 58 | { "name": "doc-assets","mode": "16384", "size":0}, 59 | { "name": "include","mode": "16384", "size":0}, 60 | { "name": "lib","mode": "16384", "size":0}, 61 | { "name": "lwsws","mode": "16384", "size":0}, 62 | { "name": "minimal-examples","mode": "16384", "size":0}, 63 | { "name": "plugin-standalone","mode": "16384", "size":0}, 64 | { "name": "plugins","mode": "16384", "size":0}, 65 | { "name": "scripts","mode": "16384", "size":0}, 66 | { "name": "test-apps","mode": "16384", "size":0}, 67 | { "name": "win32port","mode": "16384", "size":0}, 68 | { "name": ".gitignore","mode": "33188", "size":724}, 69 | { "name": ".mailmap","mode": "33188", "size":103}, 70 | { "name": ".travis.yml","mode": "33188", "size":3130}, 71 | { "name": "CMakeLists.txt","mode": "33188", "size":89374}, 72 | { "name": "Kconfig","mode": "33188", "size":857}, 73 | { "name": "LICENSE","mode": "33188", "size":2585}, 74 | { "name": "Makefile.projbuild","mode": "33188", "size":54}, 75 | { "name": "README.md","mode": "33188", "size":10248}, 76 | { "name": "appveyor.yml","mode": "33188", "size":3075}, 77 | { "name": "changelog","mode": "33188", "size":42341}, 78 | { "name": "component.mk","mode": "33188", "size":1659}, 79 | { "name": "libwebsockets.dox","mode": "33188", "size":14433}],"s":{"c":1575217508,"u": 3097}} 80 | ,{"schema":"libjg2-1", 81 | "cid":"68eb63c5e2d96476721a64ac2323fdb9", 82 | "oid":{ "oid": "bca993f7ed08e27083ea76311e5c717363a2760c", "alias": [ "refs/heads/master"]},"blobname": "README.md", "blob": "[![Travis Build Status](https://travis-ci.org/warmcat/libwebsockets.svg)](https://travis-ci.org/warmcat/libwebsockets) [![Appveyor Build status](https://ci.appveyor.com/api/projects/status/qfasji8mnfnd2r8t?svg\u003dtrue)](https://ci.appveyor.com/project/lws-team/libwebsockets) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3576/badge.svg)](https://scan.coverity.com/projects/3576) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/2266/badge)](https://bestpractices.coreinfrastructure.org/projects/2266) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/144fb195a83046e484a75c8b4c6cfc99)](https://www.codacy.com/app/lws-team/libwebsockets?utm_source\u003dgithub.com\u0026amp;utm_medium\u003dreferral\u0026amp;utm_content\u003dwarmcat/libwebsockets\u0026amp;utm_campaign\u003dBadge_Grade) [![Total alerts](https://img.shields.io/lgtm/alerts/g/warmcat/libwebsockets.svg?logo\u003dlgtm\u0026logoWidth\u003d18)](https://lgtm.com/projects/g/warmcat/libwebsockets/alerts/) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/warmcat/libwebsockets.svg?logo\u003dlgtm\u0026logoWidth\u003d18)](https://lgtm.com/projects/g/warmcat/libwebsockets/context:cpp) [![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/warmcat/libwebsockets.svg?logo\u003dlgtm\u0026logoWidth\u003d18)](https://lgtm.com/projects/g/warmcat/libwebsockets/context:javascript)\n\n# Libwebsockets\n\nLibwebsockets is a simple-to-use, pure C library providing client and server\nfor **http/1**, **http/2**, **websockets** and other protocols in a security-minded,\nlightweight, configurable, scalable and flexible way. It's easy to build and\ncross-build via cmake and is suitable for tasks from embedded RTOS through mass\ncloud serving.\n\n[50 minimal examples](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples) for\nvarious scenarios, CC0-licensed (public domain) for cut-and-paste, allow you to get started quickly.\n\n![overview](./doc-assets/lws-overview.png)\n\nNews\n----\n\n## `lws_system`: DHCP client\n\nDHCP client is now another network service that can be integrated into lws, with\n`LWS_WITH_SYS_DHCP_CLIENT` at CMake. When enabled, the `lws_system` state\nis held at `DHCP` until at least one registered network interface acquires a\nusable set of DHCP information including ip, subnet mask, router / gateway\naddress and at least one DNS server.\n\nSee the [api-test-dhcp](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-dhcpc) Minimal Example for how to use.\n\n## UDP integration with `lws_retry`\n\nUDP support in lws has new helper that allow `lws_retry` to be applied for retry,\nand the ability to synthesize rx and tx udp packetloss systemwide to confirm\nretry strategies. Since multiple transactions may be in flight on one UDP\nsocket, the support relies on an `lws_sul` in the transaction object to manage\nthe transaction retries individually.\n\nSee `READMEs/README.udp.md` for details.\n\n## `lws_system`: system state and notification handlers\n\nLws now has the concept of systemwide state held in the context... this is to\nmanage that there may be multiple steps that need the network before it's possible\nfor the user code to operate normally. The steps defined are\n\n`CONTEXT_CREATED`, `INITIALIZED`, `IFACE_COLDPLUG`, `DHCP`, `TIME_VALID`, `POLICY_VALID`,\n`REGISTERED`, `AUTH1`, `AUTH2`, `OPERATIONAL` and `POLICY_INVALID`. OPERATIONAL is the\nstate where user code can run normally.\n\nUser and other parts of lws can hook notifier callbacks to receive and be able to\nveto system state changes, either definitively or because they have been triggered\nto perform a step asynchronously and will move the state on themselves when it\ncompletes.\n\nBy default just after context creation, lws attempts to move straight to OPERATIONAL.\nIf no notifier interecepts it, it will succeed to do that and operate in a\nbackwards-compatible way. Enabling various features like lws ntpclient also enable\nnotifiers that hold progress at the related state until their operation completes\nsuccessfully, eg, not able to enter `TIME_VALID` until ntpclient has the time.\n\nSee `READMEs/README.lws_system.md` for details.\n\n## `lws_system`: HAL ops struct\n\nLws allows you to define a standardized ops struct at context creation time so your\nuser code can get various information like device serial number without embedding\nsystem-specific code throughout the user code. It can also perform some generic\nfunctions like requesting a device reboot.\n\nSee `READMEs/README.lws_system.md` for details.\n\n## `lws_system`: ntpclient\n\nOptional lws system service enabled by cmake `-DLWS_WITH_SYS_NTPCLIENT` intercepts\nthe `lws_system` `TIME_VALID` state and performs ntpclient to get the date and time\nbefore entering `TIME_VALID`. This allows user code to validate tls certificates\ncorrectly knowing the current date and time by the time it reached OPERATIONAL.\n\n## Connection Validity tracking\n\nLws now allows you to apply a policy for how long a network connection may go\nwithout seeing something on it that confirms it's still valid in the sense of\npassing traffic cohernetly both ways. There's a global policy in the context\nwhich defaults to 5m before it produces a PING if possible, and 5m10 before\nthe connection will be hung up, user code can override this in the context,\nvhost (for server) and client connection info (for client).\n\nAn api `lws_validity_confirmed(wsi)` is provided so user code can indicate\nthat it observed traffic that must mean the connection is passing traffic in\nboth directions to and from the peer. In the absence of these confirmations\nlws will generate PINGs and take PONGs as the indication of validity.\n\n## `lws_system`: Async DNS support\n\nMaster now provides optional Asynchronous (ie, nonblocking) recursive DNS resolving.\nEnable with `-DLWS_WITH_SYS_ASYNC_DNS\u003d1` at cmake. This provides a quite\nsophisticated ipv4 + ipv6 capable resolver that autodetects the dns server on\nseveral platforms and operates a UDP socket to its port 53 to produce and parse DNS\npackets from the event loop. And of course, it's extremely compact.\n\nIt broadly follows the getaddrinfo style api, but instead of creating the results\non the heap for each caller, it caches a single result according to the TTL and\nthen provides refcounted const pointers to the cached result to callers. While\nthere are references on the cached result it can't be reaped.\n\nSee `READMEs/README.async-dns.md` for detailed information on how it works, along\nwith `api-tests/api-test-async-dns` minimal example.\n\n## Detailed Latency\n\nYou can now opt to measure and store us-resolution statistics on effective\nlatencies for client operations, and easily spool them to a file in a\nformat suitable for gnuplot, or handle in your own callback. Enable\n`-DLWS_WITH_DETAILED_LATENCY\u003d1` in cmake to build it into lws.\n\nIf you are concerned about operation latency or potential blocking from\nuser code, or behaviour under load, or latency variability on specific\nplatforms, you can get real numbers on your platform using this.\n\nTimings for all aspects of events on connections are recorded, including\nthe time needed for name resolution, setting up the connection, tls\nnegotiation on both client and server sides, and each read and write.\n\nSee `READMEs/README.detailed-latency.md` for how to use it.\n\n## Client connection logic rewrite\n\nLws master now makes much better use of the DNS results for ipv4 and ipv6... it\nwill iterate through them automatically making the best use it can of what's\nprovided and attempting new connections for each potentially usable one in turn\nbefore giving up on the whole client connection attempt.\n\nIf ipv6 is disabled at cmake it can only use A / ipv4 records, but if ipv6 is\nenabled, it tries both; if only ipv6 is enabled it promotes ipv4 to\n::ffff:1.2.3.4 IPv4-in-IPv6 addresses.\n\n## New network helpers for ipv4 and ipv6\n\nAn internal union `lws_sockaddr46` that combines `struct sockaddr_in` and\n`struct sockaddr_in6` is now public, and there are helpers that can parse (using\n`lws_tokenize`) any valid numeric representation for ipv4 and ipv6 either\ninto byte arrays and lengths, or directly to and from `lws_sockaddr46`.\n\n## h2 long poll support\n\nLws now supports the convention that half-closing an h2 http stream may make\nthe stream 'immortal', in terms of not being bound by normal timeouts. For\nthe client side, there's an api that can be applied to the client stream to\nmake it transition to this \u0022read-only\u0022 long poll mode.\n\nSee `READMEs/README.h2-long-poll.md` for full details, including how to test\nit with the minimal examples.\n\n## h1 client parser improvements\n\nH1 is not so simple to parse because the header length is not known until it\nhas been fully parsed. The next header, or http body may be directly coalesced\nwith the header as well. Lws has supported bulk h1 parsing from a buffer for a\nlong time, but on clientside due to interactions with http proxying it had\nbeen stuck parsing the header bytewise out of the tls buffer. In master,\neverything now bulk parses from a buffer and uses a buflist to pass leftovers\nthrough the event loop cleanly.\n\n## `lws_sul` time refactor\n\nJust before v3.2 there was a big refactor about how lws handles time. It now\nexplicitly schedules anything that may happen in the future on a single, sorted\nlinked-list, at us resolution. When entering a poll wait (or returning to an\nevent lib loop) it checks the interval between now and the earliest event on the\nlist to figure out how long to wait if there are no network events. For the\nevent loop case, it sets a native event lib timer to enforce it.\n\nSee `READMEs/README.lws_sul.md` for more details and a handy api where you can\nschedule your own arbitrary callbacks using this system.\n\n## Master is now MIT-licensed\n\nLibwebsockets master is now under the MIT license. See ./LICENSE.\n\n## Support\n\nThis is the libwebsockets C library for lightweight websocket clients and\nservers. For support, visit\n\n https://libwebsockets.org\n\nand consider joining the project mailing list at\n\n https://libwebsockets.org/mailman/listinfo/libwebsockets\n\nYou can get the latest version of the library from git:\n\n- https://libwebsockets.org/git\n\nDoxygen API docs for master: https://libwebsockets.org/lws-api-doc-master/html/index.html\n\n","s":{"c":1575217508,"u": 3592}} 83 | ],"g": 5504,"chitpc": 0,"ehitpc": 0, 84 | "indexed":0 85 | } 86 | 87 | 88 |
89 | 90 | 91 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /dataVisualization/visualiser/npm-debug.log: -------------------------------------------------------------------------------- 1 | 0 info it worked if it ends with ok 2 | 1 verbose cli [ '/usr/bin/node', '/usr/bin/npm', 'start' ] 3 | 2 info using npm@3.5.2 4 | 3 info using node@v8.10.0 5 | 4 verbose config Skipping project config: /home/hannah/.npmrc. (matches userconfig) 6 | 5 verbose stack Error: ENOENT: no such file or directory, open '/home/hannah/package.json' 7 | 6 verbose cwd /home/hannah/Documents/SchoolProjects/Distributed/dataVisualization/visualiser 8 | 7 error Linux 4.15.0-99-generic 9 | 8 error argv "/usr/bin/node" "/usr/bin/npm" "start" 10 | 9 error node v8.10.0 11 | 10 error npm v3.5.2 12 | 11 error path /home/hannah/package.json 13 | 12 error code ENOENT 14 | 13 error errno -2 15 | 14 error syscall open 16 | 15 error enoent ENOENT: no such file or directory, open '/home/hannah/package.json' 17 | 16 error enoent ENOENT: no such file or directory, open '/home/hannah/package.json' 18 | 16 error enoent This is most likely not a problem with npm itself 19 | 16 error enoent and is related to npm not being able to find a file. 20 | 17 verbose exit [ -2, true ] 21 | -------------------------------------------------------------------------------- /dataVisualization/visualiser/resources/Location_dot_yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malties/dataVisualization/a860973e6064f43625dbf2c83c04f8ba574d3761/dataVisualization/visualiser/resources/Location_dot_yellow.png -------------------------------------------------------------------------------- /dataVisualization/visualiser/src/Queue.js: -------------------------------------------------------------------------------- 1 | class Queue 2 | { 3 | constructor() 4 | { 5 | this.items = []; 6 | } 7 | 8 | enqueue(element) 9 | { 10 | // adding element to the queue 11 | this.items.push(element); 12 | } 13 | 14 | dequeue() 15 | { 16 | // removing element from the queue 17 | // returns underflow when called 18 | // on empty queue 19 | if(this.isEmpty()) 20 | return "Underflow"; 21 | return this.items.shift(); 22 | } 23 | 24 | isEmpty() 25 | { 26 | // return true if the queue is empty. 27 | return this.items.length == 0; 28 | } 29 | } -------------------------------------------------------------------------------- /dataVisualization/visualiser/src/map.css: -------------------------------------------------------------------------------- 1 | #pauseButton { 2 | background-color: #555555; 3 | border: none; 4 | color: white; 5 | padding: 15px 32px; 6 | text-align: center; 7 | text-decoration: none; 8 | display: inline-block; 9 | font-size: 16px; 10 | } 11 | 12 | #jumbotron { 13 | padding: 20px; 14 | } 15 | 16 | #map { 17 | position: absolute; 18 | top: 20%; 19 | bottom: 20%; 20 | left: 0; 21 | right: 0; 22 | padding: 0; 23 | } 24 | 25 | #fly { 26 | display: block; 27 | position: absolute; 28 | margin: 0px auto; 29 | width: 50%; 30 | height: 40px; 31 | padding: 10px; 32 | border: none; 33 | border-radius: 3px; 34 | font-size: 12px; 35 | text-align: center; 36 | color: white; 37 | background: black; 38 | } 39 | 40 | body { 41 | background-color: #343A40; 42 | } 43 | 44 | p { 45 | font-size: 0.85em; 46 | margin: 10px; 47 | text-align: left; 48 | } 49 | 50 | .layerInfo { 51 | position: absolute; 52 | font-family: sans-serif; 53 | margin-top: 250px; 54 | margin-left: 5px; 55 | padding: 5px; 56 | width: 20%; 57 | border: 2px solid black; 58 | font-size: 14px; 59 | color: #222; 60 | background-color: #fff; 61 | border-radius: 3px; 62 | } 63 | 64 | .mapboxgl-popup { 65 | max-width: 400px; 66 | font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif; 67 | } 68 | 69 | 70 | /** 71 | * Set rules for how the map overlays 72 | * (information box, radio button style menu, and legend) will be displayed 73 | * on the page. */ 74 | 75 | .map-overlay { 76 | position: absolute; 77 | bottom: 0; 78 | right: 0; 79 | background: rgba(255, 255, 255, 0.8); 80 | margin-right: 20px; 81 | font-family: Arial, sans-serif; 82 | overflow: auto; 83 | border-radius: 3px; 84 | } 85 | 86 | #menu { 87 | position: absolute; 88 | background: rgba(255, 255, 255, 0.8); 89 | padding: 10px; 90 | font-family: "Open Sans", sans-serif; 91 | width: 380px; 92 | height: 45px; 93 | margin-bottom: 100px; 94 | } 95 | 96 | #features { 97 | top: 0; 98 | height: 100px; 99 | margin-top: 20px; 100 | width: 250px; 101 | } 102 | 103 | #legend { 104 | padding: 10px; 105 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); 106 | line-height: 18px; 107 | height: 75px; 108 | margin-bottom: 210px; 109 | width: 150px; 110 | } 111 | 112 | .legend-key { 113 | display: inline-block; 114 | border-radius: 20%; 115 | width: 10px; 116 | height: 10px; 117 | margin-right: 5px; 118 | } 119 | 120 | .navbar-default { 121 | background-color: #343332; 122 | border-color: #343332; 123 | border-radius: 0; 124 | } 125 | 126 | .navbar-default .navbar-brand, 127 | .navbar-default .navbar-brand:hover, 128 | .navbar-default .navbar-brand:focus { 129 | color: #FFF; 130 | } 131 | 132 | .navbar-default .navbar-nav>li>a { 133 | color: #FFF; 134 | } 135 | 136 | .navbar-default .navbar-nav>li>a:hover, 137 | .navbar-default .navbar-nav>li>a:focus { 138 | background-color: #343332; 139 | } 140 | 141 | .navbar-default .navbar-nav>.active>a, 142 | .navbar-default .navbar-nav>.active>a:hover, 143 | .navbar-default .navbar-nav>.active>a:focus { 144 | color: #FFF; 145 | background-color: #343332; 146 | } 147 | 148 | .navbar-default .navbar-text { 149 | color: #FFF; 150 | } 151 | 152 | .navbar-default .navbar-toggle { 153 | border-color: #343332; 154 | } 155 | 156 | .navbar-default .navbar-toggle:hover, 157 | .navbar-default .navbar-toggle:focus { 158 | background-color: #343332; 159 | } 160 | 161 | .navbar-default .navbar-toggle .icon-bar { 162 | background-color: #FFF; 163 | } -------------------------------------------------------------------------------- /dataVisualization/visualiser/src/map.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Traffic Visualizer 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 333 | 334 | 335 | 355 | 356 |
357 |
358 |

Data Visualization of Public Transportation in Gothenburg

359 |
360 |
361 |
362 |
363 |
364 |
365 | 366 | 367 | 379 | 380 | 381 | 385 | 386 | 387 |
388 |
389 | 390 | 395 | 396 | 397 | 398 | -------------------------------------------------------------------------------- /dataVisualization/visualiser/src/map.js: -------------------------------------------------------------------------------- 1 | import ('https://api.mapbox.com/mapbox-gl-js/v1.4.1/mapbox-gl.js'); 2 | mapboxgl.accessToken = 'pk.eyJ1IjoiaGFzc2Fuc2VuanUiLCJhIjoiY2szN2JtNzk4MDl5cTNjamx4cmQ5eXN5OCJ9.YwEZ5rUmNDEmJy3bCCcDPg'; 3 | var map = new mapboxgl.Map({ 4 | container: 'map', 5 | style: 'mapbox://styles/mapbox/dark-v9', 6 | center: [57.7, 11.9], 7 | zoom: 10 8 | }); 9 | document.getElementById("fly").addEventListener("click", function() { 10 | map.flyTo({ 11 | center: [57.7089, 11.9746] 12 | }) 13 | }); -------------------------------------------------------------------------------- /dataVisualization/visualiser/src/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | foo 7 | bar 8 | 1.0-SNAPSHOT 9 | 10 | 11 | 12 | maven-resources-plugin 13 | 2.5 14 | 15 | 16 | copy-resources 17 | 18 | validate 19 | 20 | copy-resources 21 | 22 | 23 | ${basedir}/target/extra-resources 24 | 25 | 26 | src/non-packaged-resources 27 | true 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /dataVisualization/visualiser/src/websockettest.html: -------------------------------------------------------------------------------- 1 | 33 | -------------------------------------------------------------------------------- /generator/GUI.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import PySimpleGUI as sg 3 | import paho.mqtt.client as paho 4 | from faker import Faker 5 | import json 6 | import datetime 7 | import time 8 | 9 | def on_publish(client,userdata,result): 10 | print("data published \n") 11 | print("userdata: " + str(userdata)) 12 | print("result: " + str(result)) 13 | pass 14 | 15 | client = paho.Client() 16 | client.on_publish = on_publish 17 | 18 | fake = Faker() 19 | 20 | requests_per_minute = 30 21 | 22 | deviceId = fake.pyint(min_value=0, max_value=9999, step=1) 23 | 24 | if len(sys.argv) == 2: 25 | sg.change_look_and_feel('DarkAmber') # Add a little color to your windows 26 | # All the stuff inside your window. This is the PSG magic code compactor... 27 | 28 | column1 = [[sg.Radio('Choose time', 'radio3')], 29 | [sg.InputText("mm", size=(4, 1)), sg.InputText("dd", size=(4, 1))], 30 | [sg.InputText("h", size=(4, 1)), sg.InputText("min", size=(4, 1))]] 31 | 32 | layout = [[sg.Text('Please enter borker')], 33 | [sg.InputText('test.mosquitto.org')], 34 | [sg.Text('Choose port')], 35 | [sg.InputText(1883)], 36 | [sg.Text('Choose one of the popular origins'), sg.Radio('random', 'radio1', default=True), 37 | sg.Radio('stadium', 'radio1')], 38 | [sg.Text('Choose one of the popular destination'), sg.Radio('random', 'radio2', default=True), 39 | sg.Radio('Lindholmspiren', 'radio2')], 40 | [sg.Radio('Use Current Time', 'radio3'), sg.Column(column1)], 41 | [sg.OK(), sg.Cancel()]] 42 | 43 | # Create the Window 44 | window = sg.Window('Configure data generator', layout) 45 | # Event Loop to process "events" 46 | while True: 47 | event, values = window.read() 48 | print(values) 49 | broker = values[0]; 50 | port = int(values[1]); 51 | client.connect(broker, port, 60) 52 | 53 | gbLat = 57.710 # latitude of the center of the city of gothenburg 54 | gbLng = 11.973 # longitude of the center of the city of gothenburg 55 | currentTime = datetime.datetime.now() 56 | startTime = datetime.datetime.now() 57 | prevTime = 0 58 | 59 | i = 0 60 | 61 | while True: 62 | if values[6] & int((datetime.datetime.now() - startTime).total_seconds()) > prevTime: 63 | prevTime = int((datetime.datetime.now() - startTime).total_seconds()) 64 | currentTime += datetime.timedelta(minutes=1) 65 | 66 | requestId = i 67 | i += 1 68 | 69 | epoch = time.time() 70 | if not values[2]: 71 | latA = 57.7072 72 | lngA = 11.9668 73 | else: 74 | latA = str(fake.coordinate(center=gbLat, radius=0.10)) 75 | lngA = str(fake.coordinate(center=gbLng, radius=0.15)) 76 | 77 | if not values[4]: 78 | latB = 57.7055 79 | lngB = 11.9399 80 | else: 81 | latB = str(fake.coordinate(center=gbLat, radius=0.10)) 82 | lngB = str(fake.coordinate(center=gbLng, radius=0.15)) 83 | 84 | if values[7]: 85 | ts = "2020-" + values[8] + "-" + values[9] + " " + values[10] + ":" + values[11] 86 | 87 | else: 88 | ts = currentTime.strftime("%Y-%m-%d %H:%M") 89 | 90 | if fake.pyint(min_value=0, max_value=1, step=1) == 0: 91 | purpose = "work" 92 | else: 93 | purpose = "leisure" 94 | 95 | json_data = { 96 | 'deviceId': deviceId, 97 | 'requestId': requestId, 98 | 'origin': { 99 | 'latitude': latA, 100 | 'longitude': lngA 101 | }, 102 | 'destination': { 103 | 'latitude': latB, 104 | 'longitude': lngB 105 | }, 106 | 'timeOfDeparture': ts, 107 | 'purpose': purpose, 108 | 'issuance': epoch 109 | } 110 | 111 | print(json.dumps(json_data, indent=4, sort_keys=True)) 112 | 113 | time.sleep(60 / requests_per_minute) 114 | client.publish("external", json.dumps(json_data)) 115 | 116 | # hour = currentTime.hour 117 | # if (hour >= 7 and hour < 9) or (hour >= 15 and hour < 18): 118 | # sleepTime = 0.1 119 | # else: 120 | # sleepTime = 1 121 | 122 | # time.sleep(sleepTime) 123 | 124 | client.disconnect() 125 | 126 | if event in (None, 'Cancel'): 127 | break 128 | else: 129 | broker = "test.mosquitto.org" 130 | port = 1883 131 | client.connect(broker, port, 60) 132 | gbLat = 57.710 # latitude of the center of the city of gothenburg 133 | gbLng = 11.973 # longitude of the center of the city of gothenburg 134 | currentTime = datetime.datetime.now() 135 | startTime = datetime.datetime.now() 136 | prevTime = 0 137 | i = 0 138 | while True: 139 | if int((datetime.datetime.now() - startTime).total_seconds()) > prevTime: 140 | prevTime = int((datetime.datetime.now() - startTime).total_seconds()) 141 | currentTime += datetime.timedelta(minutes=1) 142 | 143 | requestId = i 144 | i += 1 145 | 146 | epoch = time.time() 147 | 148 | latA = str(fake.coordinate(center=gbLat, radius=0.10)) 149 | lngA = str(fake.coordinate(center=gbLng, radius=0.15)) 150 | latB = str(fake.coordinate(center=gbLat, radius=0.10)) 151 | lngB = str(fake.coordinate(center=gbLng, radius=0.15)) 152 | 153 | ts = currentTime.strftime("%Y-%m-%d %H:%M") 154 | 155 | if fake.pyint(min_value=0, max_value=1, step=1) == 0: 156 | purpose = "work" 157 | else: 158 | purpose = "leisure" 159 | 160 | json_data = { 161 | 'deviceId': deviceId, 162 | 'requestId': requestId, 163 | 'origin': { 164 | 'latitude': latA, 165 | 'longitude': lngA 166 | }, 167 | 'destination': { 168 | 'latitude': latB, 169 | 'longitude': lngB 170 | }, 171 | 'timeOfDeparture': ts, 172 | 'purpose': purpose, 173 | 'issuance': epoch 174 | } 175 | 176 | print(json.dumps(json_data, indent=4, sort_keys=True)) 177 | 178 | time.sleep(60 / requests_per_minute) 179 | client.publish("external", json.dumps(json_data)) 180 | 181 | # hour = currentTime.hour 182 | # if (hour >= 7 and hour < 9) or (hour >= 15 and hour < 18): 183 | # sleepTime = 0.1 184 | # else: 185 | # sleepTime = 1 186 | 187 | # time.sleep(sleepTime) 188 | 189 | client.disconnect() 190 | 191 | 192 | -------------------------------------------------------------------------------- /generator/README.md: -------------------------------------------------------------------------------- 1 | **publisher.py** 2 | 3 | Generates random two points in the area of Gothenburg and a time (in format hours:minutes) and after connecting to the MQTT Broker (Mosquitto) publishes this data. 4 |

5 | 6 | **GUI.py** 7 | 8 | The same script as publisher with option of requests modification. 9 | To be able to run the GUI you need to install pysimplegui. 10 |
11 | **pip3 install pysimplegui** 12 |
13 | Run the scrpit by using the command python3 GUI.py to run the regular generator. 14 | To configure the generator, use the command python3 GUI.py followed by a random argument. 15 | ex: 16 | **python3 GUI.py custom** 17 |

18 | 19 | **subscriber.py** 20 | 21 | Subscriber is a sample of what file that is uses mqtt mosquitto and subscribes to the content publishd by publisher. 22 | It Connects to the MQTT Broker (Mosquitto) and subscribes to the same topic that the publisher is using to publish data. 23 | At every publication the data received is shown. 24 |
25 | **!! This applicative (subscriber.py) is not going to be part of the generator, it is only used for testing purposes !!** 26 | 27 | References: 28 | Steve Cope, Beginners Guide To The Paho MQTT Python Client, http://www.steves-internet-guide.com/into-mqtt-python-client/ 29 | 30 | 31 | -------------------------------------------------------------------------------- /generator/database.py: -------------------------------------------------------------------------------- 1 | import paho.mqtt.client as paho 2 | import pymongo 3 | 4 | myclient = pymongo.MongoClient("mongodb://localhost:27017/") 5 | mydb = myclient["vasttrafik"] 6 | 7 | broker="localhost" 8 | port=1883 9 | 10 | def on_connect(client, userdata, flags, rc): 11 | print("Connected with result code "+str(rc)) 12 | client.subscribe("apicaller/data") 13 | 14 | def on_message(client, userdata, msg): 15 | print("Message received:") 16 | print(str(msg.topic) + " " + str(msg.payload.decode())) 17 | 18 | message = msg.payload.decode() 19 | print(message) 20 | 21 | mycol = mydb["datapoints"] 22 | mydict = { "name": "John", "address": "Highway 37" } 23 | x = mycol.insert_one(mydict) 24 | 25 | client = paho.Client() 26 | client.connect(broker,port,60) 27 | 28 | client.on_connect = on_connect 29 | client.on_message = on_message 30 | 31 | client.loop_forever() -------------------------------------------------------------------------------- /generator/publisher.py: -------------------------------------------------------------------------------- 1 | import paho.mqtt.client as paho 2 | from faker import Faker 3 | import json 4 | import datetime 5 | import time 6 | 7 | def on_publish(client,userdata,result): 8 | print("data published \n") 9 | print("userdata: " + str(userdata)) 10 | print("result: " + str(result)) 11 | pass 12 | 13 | fake = Faker() 14 | 15 | requests_per_minute = 30 16 | 17 | broker="test.mosquitto.org" 18 | port=1883 19 | 20 | deviceId = fake.pyint(min_value=0, max_value=9999, step=1) 21 | 22 | # the coordinates are generated in the area of gothenburg 23 | 24 | gbLat = 57.710 # latitude of the center of the city of gothenburg 25 | gbLng = 11.973 # longitude of the center of the city of gothenburg 26 | 27 | # RUSH HOURS 7 to 9, 15 to 18 28 | client = paho.Client() 29 | client.on_publish = on_publish 30 | client.connect(broker,port,60) 31 | 32 | currentTime = datetime.datetime.now() 33 | 34 | startTime = datetime.datetime.now() 35 | prevTime = 0 36 | 37 | i=0 38 | 39 | while True: 40 | if int((datetime.datetime.now() - startTime).total_seconds()) > prevTime: 41 | prevTime = int((datetime.datetime.now() - startTime).total_seconds()) 42 | currentTime += datetime.timedelta(minutes=1) 43 | 44 | requestId = i 45 | i+=1 46 | 47 | epoch = time.time() 48 | 49 | latA = str(fake.coordinate(center=gbLat, radius=0.10)) 50 | lngA = str(fake.coordinate(center=gbLng, radius=0.15)) 51 | latB = str(fake.coordinate(center=gbLat, radius=0.10)) 52 | lngB = str(fake.coordinate(center=gbLng, radius=0.15)) 53 | 54 | ts = currentTime.strftime("%Y-%m-%d %H:%M") 55 | 56 | if fake.pyint(min_value=0, max_value=1, step=1) == 0: 57 | purpose = "work" 58 | else: 59 | purpose = "leisure" 60 | 61 | json_data = { 62 | 'deviceId': deviceId, 63 | 'requestId': requestId, 64 | 'origin':{ 65 | 'latitude': latA, 66 | 'longitude': lngA 67 | }, 68 | 'destination':{ 69 | 'latitude': latB, 70 | 'longitude': lngB 71 | }, 72 | 'timeOfDeparture': ts, 73 | 'purpose': purpose, 74 | 'issuance' : epoch 75 | } 76 | 77 | print(json.dumps(json_data, indent=4, sort_keys=True)) 78 | 79 | time.sleep(60/requests_per_minute) 80 | client.publish("external", json.dumps(json_data)) 81 | 82 | #hour = currentTime.hour 83 | #if (hour >= 7 and hour < 9) or (hour >= 15 and hour < 18): 84 | # sleepTime = 0.1 85 | #else: 86 | # sleepTime = 1 87 | 88 | #time.sleep(sleepTime) 89 | 90 | client.disconnect() 91 | -------------------------------------------------------------------------------- /generator/subscriber.py: -------------------------------------------------------------------------------- 1 | import paho.mqtt.client as paho 2 | broker="localhost" 3 | port=1883 4 | 5 | def on_connect(client, userdata, flags, rc): 6 | print("Connected with result code "+str(rc)) 7 | client.subscribe("generator/points") 8 | 9 | def on_message(client, userdata, msg): 10 | print("Message received:") 11 | print(str(msg.topic) + " " + str(msg.payload.decode())) 12 | 13 | message = msg.payload.decode() 14 | divided = message.split(",") 15 | print(divided[0] + " " + divided[1] + " " + divided[2] + " " + divided[3]) 16 | print(divided[4]) 17 | 18 | client = paho.Client() 19 | client.connect(broker,port,60) 20 | 21 | client.on_connect = on_connect 22 | client.on_message = on_message 23 | 24 | client.loop_forever() --------------------------------------------------------------------------------