Skip to content
This repository was archived by the owner on Feb 23, 2022. It is now read-only.

Commit 48563d8

Browse files
Initial commit
0 parents  commit 48563d8

10 files changed

+242
-0
lines changed

.gitattributes

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Repo

chat.sentiment.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
$.setPortCallback("in",onInput);
2+
3+
function onInput(ctx,s) {
4+
5+
$.out(s.Attributes["polarity"]);
6+
}

iot.laptop.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# import requests # http://docs.python-requests.org/en/master/
2+
import psutil # https://pypi.python.org/pypi/psutil
3+
import time
4+
import uuid
5+
import json
6+
# import sys, platform # if need to read system params, like OS type
7+
8+
def readCPU():
9+
return psutil.cpu_percent(percpu=False, interval=1)
10+
11+
def readMEM():
12+
return psutil.virtual_memory().percent
13+
14+
def readPayload():
15+
16+
d_pctCPU = readCPU()
17+
d_pctMEM = readMEM()
18+
d_tstamp = int(round(time.time()))
19+
api.logger.debug("\nValues to post: {} {}".format(d_pctCPU, d_tstamp))
20+
21+
payload = { 'guid' : deviceUIID, 'timestmp' : d_tstamp, 'cpu_load' : d_pctCPU, 'mem_load' : d_pctMEM }
22+
# api.logger.debug("\nPayload: ", str(payload))
23+
24+
return json.dumps(payload)
25+
26+
def do_tick():
27+
api.send("payload", readPayload())
28+
29+
30+
global deviceUIID
31+
deviceUIID = str(uuid.uuid1())
32+
33+
intervalMs = int(api.config.intervalMs)
34+
if intervalMs < 1001:
35+
intervalMs = 1001
36+
37+
api.add_timer(str(intervalMs-1000)+"ms", do_tick)

iot.process.final.py

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import time
2+
import locale
3+
import json
4+
#import ast
5+
6+
# Number of max devices
7+
max_devices_qty = 100
8+
9+
locale.setlocale(locale.LC_ALL,"")
10+
11+
def main(payload):
12+
last_timestamp = int(round(time.time()))
13+
ubody = payload.body.decode("utf-8") # Must be converted to Unicode first
14+
15+
#body = ast.literal_eval(ubody) #ast.literal_eval works only with strings, but can be improperly formatted JSON, like a result of str(json_object)
16+
17+
body=json.loads(ubody)
18+
body['loc_timestmp'] = last_timestamp
19+
send_blob(json.dumps([body]))
20+
21+
guid = body["guid"]
22+
del body["guid"]
23+
devices[guid] = body
24+
25+
message = ""
26+
message = generate_html_head(message)
27+
message = generate_html_body(message, last_timestamp)
28+
send_html(message)
29+
30+
# Generates head of HTML/CSS, including Style parameters
31+
def generate_html_head(message):
32+
message += '''
33+
34+
<head>
35+
<style>
36+
body {
37+
font-family: Verdana, Geneva, sans-serif;
38+
background: #b5b5bf;
39+
}
40+
table.dataTable {
41+
border: 1px solid #1C6EA4;
42+
background-color: #EEEEEE;
43+
text-align: center;
44+
border-collapse: collapse;
45+
}
46+
table.dataTable td, table.dataTable th {
47+
border: 2px solid #AAAAAA;
48+
padding: 3px 2px;
49+
}
50+
table.dataTable tbody td {
51+
font-size: 15px;
52+
}
53+
table.dataTable thead {
54+
background: #1C6EA4;
55+
background: -moz-linear-gradient(top, #5592bb 0%, #327cad 66%, #1C6EA4 100%);
56+
background: -webkit-linear-gradient(top, #5592bb 0%, #327cad 66%, #1C6EA4 100%);
57+
background: linear-gradient(to bottom, #5592bb 0%, #327cad 66%, #1C6EA4 100%);
58+
border-bottom: 2px solid #888888;
59+
}
60+
table.dataTable thead th {
61+
font-size: 15px;
62+
font-weight: bold;
63+
color: #FFFFFF;
64+
text-align: center;
65+
border-left: 2px solid #D0E4F5;
66+
}
67+
table.dataTable thead th:first-child {
68+
border-left: none;
69+
}
70+
71+
table.dataTable tfoot td {
72+
font-size: 14px;
73+
}
74+
table.dataTable tfoot .links {
75+
text-align: right;
76+
}
77+
table.dataTable tfoot .links a{
78+
display: inline-block;
79+
background: #1C6EA4;
80+
color: #FFFFFF;
81+
padding: 2px 8px;
82+
border-radius: 5px;
83+
}
84+
</style>
85+
</head>
86+
'''
87+
return message
88+
89+
# Concatenates HTML body to previously generated head.
90+
def generate_html_body(message, last_timestamp):
91+
# Title, description and table header
92+
message += '''
93+
94+
<body>
95+
<center>
96+
97+
<h2> Prototype IoT Data Viewer </h2>
98+
<br>
99+
</center>
100+
<p style="margin-left:15%; margin-right:15%"> The purpose of this Graph is to serve as a stub for the HTML Viewer operator.
101+
Combining the HTML Viewer with a Python Operator, it is possible to adapt IoT data for real time display in a simple and flexible manner.
102+
103+
<br><br>
104+
The data structure generation is happening in the Python3 Operator, which is messaging a String containing an HTML page to the HTML Viewer
105+
through WebSocket with every update. The HTML Viewer then updates the display as soon as a message is received.
106+
<br><br>
107+
</p>
108+
109+
<center>
110+
Last time stamp: {}
111+
<br><br>
112+
113+
114+
<table class="dataTable" id="salesTable">
115+
<thead>
116+
<tr>
117+
<th style="width:400px"> Device UUID </th>
118+
<th style="width:300px"> Last timestamp </th>
119+
<th style="width:100px"> CPU % </th>
120+
<th style="width:100px"> Mem % </th>
121+
</tr>
122+
</thead>
123+
<tbody>
124+
'''.format(time.ctime(round(time.time())))
125+
126+
# Iterates each store to add them to table
127+
for i in devices:
128+
message += '''
129+
<tr>
130+
<td> {} </td>
131+
<td> {} </td>
132+
<td> {} %</td>
133+
<td> {} %</td>
134+
</tr>
135+
'''.format(
136+
i,
137+
time.ctime(int(devices[i]["timestmp"])),
138+
locale.format("%.2f", devices[i]["cpu_load"], 1),
139+
locale.format("%.2f", devices[i]["mem_load"], 1)
140+
)
141+
142+
message += '''
143+
</tbody>
144+
</table>
145+
<br><br>
146+
</center>
147+
</body>
148+
'''
149+
return message
150+
151+
# Sends the String containing HTML page through WebSocket
152+
def send_html(message):
153+
api.send("outhtml", message)
154+
155+
# Sends the String containing HTML page through WebSocket
156+
def send_blob(blb):
157+
api.send("outblob", blb)
158+
159+
api.send("outhtml", "Waiting for data...")
160+
devices = {} #Empty dictionary
161+
162+
api.set_port_callback("inmsg", main)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Use an official Python 3.6 image as a parent image
2+
FROM python3.6.4-stretch
3+
4+
# Install python library psutil
5+
RUN apt-get update
6+
&& apt-get upgrade -y
7+
&& apt-get install -y gcc python3-dev
8+
RUN pip3 install psutil
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"properties":{},"iconsrc":"","icon":"heart","description":"MQTT-TCP-based Chat with sentiment analysis","processes":{"terminal1":{"component":"com.sap.util.terminal","metadata":{"label":"Terminal","x":550.9999980926514,"y":12,"height":80,"width":120,"ui":"dynpath","config":{}}},"mqttconsumer21":{"component":"com.sap.mqtt.consumer","metadata":{"label":"MQTT Consumer","x":12,"y":72,"height":80,"width":120,"config":{"mqttBroker":"tcp://test.mosquitto.org:1883","topic":"sapcodejam/+/chat/#","numRetryAttempts":"3","retryPeriodInMs":"50"}}},"mqttproducer2":{"component":"com.sap.mqtt.producer","metadata":{"label":"MQTT Producer","x":719.9999980926514,"y":12,"height":80,"width":120,"config":{"mqttBroker":"tcp://test.mosquitto.org:1883","topic":"sapcodejam/wroclaw/chat/dh24_docker_windows"}}},"tostringconverter2":{"component":"com.sap.util.toStringConverter","metadata":{"label":"ToString Converter","x":400.4999990463257,"y":27,"height":50,"width":50,"config":{}}},"12multiplexer1":{"component":"com.sap.system.multiplexer.1-2","metadata":{"label":"1:2 Multiplexer","x":181,"y":72,"height":80,"width":120,"extensible":true,"config":{}}},"sentimentanalyser1":{"component":"com.sap.ml.nlp.sentimentAnalyser","metadata":{"label":"Sentiment Analyser","x":365.9999990463257,"y":117,"height":80,"width":120,"extensible":true,"config":{}}},"wiretap2":{"component":"com.sap.util.wiretap","metadata":{"label":"Wiretap","x":550.9999980926514,"y":132,"height":80,"width":120,"ui":"dynpath","config":{}}},"wiretap3":{"component":"com.sap.util.wiretap","metadata":{"label":"Wiretap","x":904.999997138977,"y":72,"height":80,"width":120,"ui":"dynpath","config":{}}},"blankjsoperator1":{"component":"com.sap.system.jsoperator","metadata":{"label":"Blank JS Operator","x":719.9999980926514,"y":132,"height":80,"width":120,"extensible":true,"config":{"script":"$.setPortCallback(\"in\",onInput);\n\nfunction isByteArray(data) {\n switch (Object.prototype.toString.call(data)) {\n case \"[object Int8Array]\":\n case \"[object Uint8Array]\":\n return true;\n case \"[object Array]\":\n case \"[object GoArray]\":\n return data.length > 0 && typeof data[0] === 'number';\n }\n return false;\n}\n\nfunction onInput(ctx,s) {\n\n $.out(s.Attributes[\"polarity\"]);\n}"},"additionalinports":[{"name":"in","type":"message"}],"additionaloutports":[{"name":"out","type":"float64"}]}},"histogram2":{"component":"com.sap.util.histogram","metadata":{"label":"Histogram","x":1073.999997138977,"y":72,"height":80,"width":120,"config":{"nBins":5,"rangeMin":-1}}},"histogramplotter2":{"component":"com.sap.util.histogramPlotter","metadata":{"label":"Histogram Plotter","x":1357.9999961853027,"y":72,"height":80,"width":120,"ui":"dynpath","config":{}}},"tostringconverter3":{"component":"com.sap.util.toStringConverter","metadata":{"label":"ToString Converter","x":1258.9999961853027,"y":87,"height":50,"width":50,"config":{}}}},"groups":[],"connections":[{"metadata":{"points":"454.4999990463257,52 545.9999980926514,52"},"src":{"port":"outstring","process":"tostringconverter2"},"tgt":{"port":"in1","process":"terminal1"}},{"metadata":{"points":"674.9999980926514,52 714.9999980926514,52"},"src":{"port":"out1","process":"terminal1"},"tgt":{"port":"inmessage","process":"mqttproducer2"}},{"metadata":{"points":"305,103 332.99999952316284,103 332.99999952316284,61 395.4999990463257,61"},"src":{"port":"out1","process":"12multiplexer1"},"tgt":{"port":"inmessage","process":"tostringconverter2"}},{"metadata":{"points":"305,121 332.99999952316284,121 332.99999952316284,157 360.9999990463257,157"},"src":{"port":"out2","process":"12multiplexer1"},"tgt":{"port":"in","process":"sentimentanalyser1"}},{"metadata":{"points":"489.9999990463257,157 517.9999985694885,157 517.9999985694885,172 545.9999980926514,172"},"src":{"port":"out","process":"sentimentanalyser1"},"tgt":{"port":"in","process":"wiretap2"}},{"metadata":{"points":"674.9999980926514,172 714.9999980926514,172"},"src":{"port":"out","process":"wiretap2"},"tgt":{"port":"in","process":"blankjsoperator1"}},{"metadata":{"points":"843.9999980926514,172 871.9999976158142,172 871.9999976158142,112 899.999997138977,112"},"src":{"port":"out","process":"blankjsoperator1"},"tgt":{"port":"in","process":"wiretap3"}},{"metadata":{"points":"1028.999997138977,112 1068.999997138977,112"},"src":{"port":"out","process":"wiretap3"},"tgt":{"port":"histIn","process":"histogram2"}},{"metadata":{"points":"1312.9999961853027,112 1352.9999961853027,112"},"src":{"port":"outstring","process":"tostringconverter3"},"tgt":{"port":"in1","process":"histogramplotter2"}},{"metadata":{"points":"1197.999997138977,112 1225.99999666214,112 1225.99999666214,121 1253.9999961853027,121"},"src":{"port":"histOut","process":"histogram2"},"tgt":{"port":"inmessage","process":"tostringconverter3"}},{"metadata":{"points":"136,112 176,112"},"src":{"port":"outmessage","process":"mqttconsumer21"},"tgt":{"port":"in1","process":"12multiplexer1"}}],"inports":{},"outports":{}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"properties":{},"icon":"area-chart","description":"Process IoT data","processes":{"mqttconsumer01":{"component":"com.sap.mqtt.consumer","metadata":{"label":"MQTT Consumer","x":12,"y":72,"height":80,"width":120,"config":{"mqttBroker":"tcp://test.mosquitto.org:1883","topic":"sapcodejam/+/iot","numRetryAttempts":"3","retryPeriodInMs":"200"}}},"htmlviewer1":{"component":"com.sap.util.htmlViewer","metadata":{"label":"HTML Viewer","x":365.9999990463257,"y":12,"height":80,"width":120,"ui":"dynpath","config":{}}},"python3operator1":{"component":"com.sap.system.python3Operator","metadata":{"label":"Python3Operator","x":181,"y":72,"height":80,"width":120,"extensible":true,"config":{"script":"import time\nimport locale\nimport json\n#import ast\n\n# Number of max devices\nmax_devices_qty = 100\n\nlocale.setlocale(locale.LC_ALL,\"\")\n\ndef main(payload):\n last_timestamp = int(round(time.time()))\n ubody = payload.body.decode(\"utf-8\") # Must be converted to Unicode first\n \n #body = ast.literal_eval(ubody) #ast.literal_eval works only with strings, but can be improperly formatted JSON, like a result of str(json_object)\n \n body=json.loads(ubody)\n body['loc_timestmp'] = last_timestamp\n send_blob(json.dumps([body]))\n \n guid = body[\"guid\"]\n del body[\"guid\"]\n devices[guid] = body\n \n message = \"\"\n message = generate_html_head(message)\n message = generate_html_body(message, last_timestamp)\n send_html(message)\n\n# Generates head of HTML/CSS, including Style parameters\ndef generate_html_head(message):\n message += '''\n\n<head>\n<style>\nbody {\n font-family: Verdana, Geneva, sans-serif;\n background: #b5b5bf;\n}\ntable.dataTable {\n border: 1px solid #1C6EA4;\n background-color: #EEEEEE;\n text-align: center;\n border-collapse: collapse;\n}\ntable.dataTable td, table.dataTable th {\n border: 2px solid #AAAAAA;\n padding: 3px 2px;\n}\ntable.dataTable tbody td {\n font-size: 15px;\n}\ntable.dataTable thead {\n background: #1C6EA4;\n background: -moz-linear-gradient(top, #5592bb 0%, #327cad 66%, #1C6EA4 100%);\n background: -webkit-linear-gradient(top, #5592bb 0%, #327cad 66%, #1C6EA4 100%);\n background: linear-gradient(to bottom, #5592bb 0%, #327cad 66%, #1C6EA4 100%);\n border-bottom: 2px solid #888888;\n}\ntable.dataTable thead th {\n font-size: 15px;\n font-weight: bold;\n color: #FFFFFF;\n text-align: center;\n border-left: 2px solid #D0E4F5;\n}\ntable.dataTable thead th:first-child {\n border-left: none;\n}\n\ntable.dataTable tfoot td {\n font-size: 14px;\n}\ntable.dataTable tfoot .links {\n text-align: right;\n}\ntable.dataTable tfoot .links a{\n display: inline-block;\n background: #1C6EA4;\n color: #FFFFFF;\n padding: 2px 8px;\n border-radius: 5px;\n}\n</style>\n</head>\n '''\n return message\n\n# Concatenates HTML body to previously generated head.\ndef generate_html_body(message, last_timestamp):\n # Title, description and table header\n message += '''\n\n<body>\n<center>\n\n<h2> Prototype IoT Data Viewer </h2>\n<br>\n</center>\n<p style=\"margin-left:15%; margin-right:15%\"> The purpose of this Graph is to serve as a stub for the HTML Viewer operator. \nCombining the HTML Viewer with a Python Operator, it is possible to adapt IoT data for real time display in a simple and flexible manner.\n\n<br><br>\nThe data structure generation is happening in the Python3 Operator, which is messaging a String containing an HTML page to the HTML Viewer \nthrough WebSocket with every update. The HTML Viewer then updates the display as soon as a message is received.\n<br><br>\n</p>\n\n<center>\nLast time stamp: {}\n<br><br>\n\n\n<table class=\"dataTable\" id=\"salesTable\">\n<thead>\n<tr>\n<th style=\"width:400px\"> Device UUID </th>\n<th style=\"width:300px\"> Last timestamp </th>\n<th style=\"width:100px\"> CPU % </th>\n<th style=\"width:100px\"> Mem % </th>\n</tr>\n</thead>\n<tbody>\n '''.format(time.ctime(round(time.time())))\n\n # Iterates each store to add them to table\n for i in devices:\n message += '''\n<tr>\n<td> {} </td>\n<td> {} </td>\n<td> {} %</td>\n<td> {} %</td> \n</tr>\n '''.format(\n i, \n time.ctime(int(devices[i][\"timestmp\"])),\n locale.format(\"%.2f\", devices[i][\"cpu_load\"], 1),\n locale.format(\"%.2f\", devices[i][\"mem_load\"], 1)\n )\n\n message += '''\n</tbody>\n</table>\n<br><br>\n</center>\n</body>\n '''\n return message\n\n# Sends the String containing HTML page through WebSocket\ndef send_html(message):\n api.send(\"outhtml\", message)\n\n# Sends the String containing HTML page through WebSocket\ndef send_blob(blb):\n api.send(\"outblob\", blb)\n\napi.send(\"outhtml\", \"Waiting for data...\")\ndevices = {} #Empty dictionary\n\napi.set_port_callback(\"inmsg\", main)"},"additionalinports":[{"name":"inmsg","type":"message"}],"additionaloutports":[{"name":"outhtml","type":"string"},{"name":"outblob","type":"blob"}]}},"wiretap1":{"component":"com.sap.util.wiretap","metadata":{"label":"Wiretap","x":719.9999980926514,"y":72,"height":80,"width":120,"ui":"dynpath","config":{}}},"formatconverter1":{"component":"com.sap.util.formatConverter","metadata":{"label":"Format Converter","x":365.9999990463257,"y":132,"height":80,"width":120,"config":{"targetFormat":"CSV","fields":"guid,timestmp,cpu_load,mem_load,loc_timestmp"}}},"writefile1":{"component":"com.sap.storage.write","metadata":{"label":"Write File","x":550.9999980926514,"y":72,"height":80,"width":120,"config":{"service":"hdfs","hadoopConnection":{"connectionProperties":{"host":"hdfs","port":9000,"user":"root","protocol":"rpc"},"configurationType":"Manual"},"path":"/tmp/iot/load_<date>.csv"}}}},"groups":[],"connections":[{"metadata":{"points":"305,103 332.99999952316284,103 332.99999952316284,52 360.9999990463257,52"},"src":{"port":"outhtml","process":"python3operator1"},"tgt":{"port":"in1","process":"htmlviewer1"}},{"metadata":{"points":"305,121 332.99999952316284,121 332.99999952316284,172 360.9999990463257,172"},"src":{"port":"outblob","process":"python3operator1"},"tgt":{"port":"input","process":"formatconverter1"}},{"metadata":{"points":"489.9999990463257,172 517.9999985694885,172 517.9999985694885,112 545.9999980926514,112"},"src":{"port":"output","process":"formatconverter1"},"tgt":{"port":"inFile","process":"writefile1"}},{"metadata":{"points":"674.9999980926514,112 714.9999980926514,112"},"src":{"port":"outFilename","process":"writefile1"},"tgt":{"port":"in","process":"wiretap1"}},{"metadata":{"points":"136,112 176,112"},"src":{"port":"outmessage","process":"mqttconsumer01"},"tgt":{"port":"inmsg","process":"python3operator1"}}],"inports":{},"outports":{}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"properties":{},"icon":"laptop","description":"Laptop as IoT Device (Py3) on MQTT-TCP","processes":{"mqttproducer01":{"component":"com.sap.mqtt.producer","metadata":{"label":"MQTT Producer","x":181,"y":12,"height":80,"width":120,"config":{"mqttBroker":"tcp://test.mosquitto.org:1883","topic":"sapcodejam/wroclaw/iot","numRetryAttempts":"3","retryPeriodInMs":"100"}}},"laptopasiot1":{"component":"codejam.iot.laptop","metadata":{"label":"Laptop as IoT","x":12,"y":12,"height":80,"width":120,"extensible":true,"config":{}}}},"groups":[],"connections":[{"metadata":{"points":"136,52 176,52"},"src":{"port":"payload","process":"laptopasiot1"},"tgt":{"port":"inmessage","process":"mqttproducer01"}}],"inports":{},"outports":{}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"component": "com.sap.system.python3Operator",
3+
"description": "Laptop as IoT",
4+
"inports": [],
5+
"outports": [
6+
{
7+
"name": "payload",
8+
"type": "string"
9+
}
10+
],
11+
"tags": {},
12+
"subenginestags": {
13+
"com.sap.python36": {
14+
"python36": "",
15+
"python_psutil": ""
16+
}
17+
},
18+
"config": {
19+
"intervalMs": 2000,
20+
"script": "# import requests # http://docs.python-requests.org/en/master/\nimport psutil # https://pypi.python.org/pypi/psutil\nimport time\nimport uuid\nimport json\n# import sys, platform # if need to read system params, like OS type\n\ndef readCPU():\n return psutil.cpu_percent(percpu=False, interval=1)\n\t\ndef readMEM():\n return psutil.virtual_memory().percent\n\ndef readPayload():\n\n\td_pctCPU = readCPU()\n\td_pctMEM = readMEM()\n\td_tstamp = int(round(time.time()))\n\tapi.logger.debug(\"\\nValues to post: {} {}\".format(d_pctCPU, d_tstamp))\n\n\tpayload = { 'guid' : deviceUIID, 'timestmp' : d_tstamp, 'cpu_load' : d_pctCPU, 'mem_load' : d_pctMEM }\n\t# api.logger.debug(\"\\nPayload: \", str(payload))\n\n\treturn json.dumps(payload)\n\ndef do_tick():\n api.send(\"payload\", readPayload())\n\n\nglobal deviceUIID \ndeviceUIID = str(uuid.uuid1())\n\nintervalMs = int(api.config.intervalMs)\nif intervalMs < 1001:\n intervalMs = 1001\n \napi.add_timer(str(intervalMs-1000)+\"ms\", do_tick)"
21+
},
22+
"icon": "laptop"
23+
}

0 commit comments

Comments
 (0)