├── .gitignore ├── LICENSE.txt ├── MANIFEST ├── README.md ├── README.th.md ├── examples └── basic.py ├── microgear ├── __init__.py ├── cache.py └── client.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | 47 | # Translations 48 | *.mo 49 | *.pot 50 | 51 | # Django stuff: 52 | *.log 53 | 54 | # Sphinx documentation 55 | docs/_build/ 56 | 57 | # PyBuilder 58 | target/ 59 | 60 | *.cache 61 | .DS_Store -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2015, NECTEC 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 8 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | # file GENERATED by distutils, do NOT edit 2 | setup.py 3 | microgear\__init__.py 4 | microgear\cache.py 5 | microgear\client.py 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Microgear-python 2 | ----------- 3 | microgear- python is a client library for Python The library is used to connect application code or hardware with the NETPIE Platform's service for developing IoT applications. For more details on the NETPIE Platform, please visit https://netpie.io . 4 | 5 | ## Outgoing Network Port 6 | ----------- 7 | Make sure ther following ports are allowed to connect from your network. 8 | - Non-TLS mode : 8080 and 1883 (microgear-python uses this mode by default) 9 | - TLS mode : 8081 and 8883 10 | 11 | ## Installation 12 | ----------- 13 | ```sh 14 | $ pip install microgear 15 | ``` 16 | 17 | 18 | ## Usage Example 19 | ----------- 20 | ```python 21 | import microgear.client as microgear 22 | import logging 23 | import time 24 | 25 | appid = 26 | gearkey = 27 | gearsecret = 28 | 29 | microgear.create(gearkey,gearsecret,appid,{'debugmode': True}) 30 | 31 | def connection(): 32 | logging.info("Now I am connected with netpie") 33 | 34 | def subscription(topic,message): 35 | logging.info(topic+" "+message) 36 | 37 | def disconnect(): 38 | logging.info("disconnected") 39 | 40 | microgear.setalias("doraemon") 41 | microgear.on_connect = connection 42 | microgear.on_message = subscription 43 | microgear.on_disconnect = disconnect 44 | microgear.subscribe("/mails") 45 | microgear.connect(True) 46 | 47 | ``` 48 | [More examples](https://github.com/netpieio/microgear-python/wiki#%E0%B8%95%E0%B8%B1%E0%B8%A7%E0%B8%AD%E0%B8%A2%E0%B9%88%E0%B8%B2%E0%B8%87%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B9%83%E0%B8%8A%E0%B9%89%E0%B8%87%E0%B8%B2%E0%B8%99) 49 | 50 | 51 | ## Library Usage 52 | ------------ 53 | ### Microgear 54 | --------------- 55 | **microgear.create(*gearkey*,*gearsecret*,*appid*,*args*):** 56 | 57 | arguments 58 | 59 | * *gearkey* `string` - is used as a microgear identity 60 | * *gearsecret* `string` - comes in a pair with gearkey. The secret is used for authentication and integrity. 61 | * *appid* `string` - defines a group of application that microgear is part of 62 | * *args* `dictionary` - sets additional options for microgear 63 | * *debugmode* `boolean` - show debug messages 64 | * *scope* `string` - This can be specified when the microgear needs additional rights beyond default scope. If the scope is specified, it may need an approval from the Application ID's owner for each request. The scope format is the concatenation of strings in the following forms, separated with commas: 65 | * [r][w]:</topic/path> - r and w is the right to publish and subscribe topic as specified such as rw:/outdoor/temp 66 | * name:<gearname> - is the right to name the <gearname> 67 | * chat:<gearname> - is the right to chat with <gearname> 68 | * *alias* string - defines a name for this microgear. The name will appear on the key management page at the website http://netpie.io. This name can be use in the `chat()` function. 69 | 70 | In the key generation process on the web netpie.io, the developer can specify basic rights to each key. If the creation of microgear is within right scope, a token will be automatically issued, and the microgear can be connected to NETPIE immediately. However, if the requested scope is beyond the specified right, the developer will recieve a notification to approve a microgear's connection. Note that if the microgear has operations beyond its right (e.g., pulishing to the topic that it does not has the right to do so), NETPIE will automatically disconnect the microgear. In case that APPKEY is used as a gearkey, the developer can ignore this attribute since by default the APPKEY will gain all rights as the ownwer of the app. 71 | 72 | 73 | ```python 74 | gearkey = 75 | gearsecret = 76 | appid = 77 | 78 | microgear.create(gearkey,gearsecret,appid, {'debugmode': True, 'scope': "r:/outdoor/temp,w:/outdoor/valve,name:logger,chat:plant", 'alias': "logger"}) 79 | ``` 80 | 81 | 82 | 83 | 84 | **microgear.connect(*will_block*):** microgear connection 85 | 86 | argument 87 | 88 | * *will_block* `boolean` - `(optional)`specifies connection type whether to block after this function. The default value is `False` so the program will execute the next line after microgear is connected to the platform. For example, 89 | 90 | ```python 91 | microgear.connect() 92 | while True: 93 | microgear.chat("doraemon","Hello world. "+str(int(time.time()))) 94 | time.sleep(2) 95 | ``` 96 | If you want the library to Block after being connected to the platform, you could wait for specified events using callback (on_*). In this case, use the argument `True` for this function. For example, 97 | ```python 98 | microgear.connect(True) 99 | ``` 100 | 101 | 102 | 103 | 104 | **microgear.setalias(*alias*):** microgear can set its own alias, which to be used for others make a function call chat(). The alias will appear on the key management portal of netpie.io . 105 | 106 | argument 107 | 108 | * *alias* `string` - name of this microgear 109 | 110 | 111 | 112 | ```python 113 | microgear.setalias("python"); 114 | ``` 115 | 116 | **microgear.setname(*gearname*):** microgear can set its own name to use with chat() **This function is deprecated. Please use `setalias()` instead** 117 | 118 | argument 119 | 120 | * *gearname* `string` - name of this microgear 121 | 122 | 123 | 124 | ```python 125 | microgear.setname("python"); 126 | ``` 127 | 128 | **microgear.chat(*gearname*, *message*):** sending a message to a specified gearname 129 | 130 | arguments 131 | 132 | * *gearname* `string` - name of microgear to which to send a message. 133 | * *message* `string` - message to be sent. 134 | 135 | ```python 136 | microgear.chat("html","hello from python"); 137 | ``` 138 | 139 | **microgear.publish(*topic*, *message*, *retain*):** In the case that the microgear want to send a message to an unspecified receiver, the developer can use the function publish to the desired topic, which all the microgears that subscribe such topic will receive a message. 140 | 141 | arguments 142 | 143 | * *topic* `string` - name of topic to be send a message to. 144 | * *message* `string` - message to be sent. 145 | * *args* `dictionary` - sets additional options for microgear 146 | * *retain* `boolean` - retain a message or not (the default is `False`) If `True`, the message is kept. To remove the retained message, publish an empty message or "" which is a message with length 0. 147 | 148 | ```python 149 | microgear.publish("/outdoor/temp","28.5"); 150 | microgear.publish("/outdoor/temp","28.5",{'retain':True}); 151 | ``` 152 | 153 | 154 | 155 | **microgear.subscribe(*topic*)** microgear may be interested in some topic. The developer can use the function subscribe() to subscribe a message belong to such topic. If the topic used to retain a message, the microgear will receive a message everytime it subscribes that topic. 156 | 157 | argument 158 | 159 | * *topic* `string` - name of the topic to send a message to. Should start with "/". 160 | 161 | 162 | 163 | ```python 164 | microgear.subscribe("/temp"); 165 | ``` 166 | 167 | **microgear.resettoken()** For deleting Token in cache and on the platform. If deleted, need to get a new Token for the next connection. 168 | 169 | ```python 170 | microgear.resettoken(); 171 | ``` 172 | 173 | **microgear.writeFeed(*feedid*, *data*, *apikey*):** write time series data to a feed storage 174 | 175 | arguments 176 | 177 | * *feedid* `string` - name of the feed 178 | * *data* `dict` – data dict 179 | * *apikey* `string` - apikey for authorization. If apikey is not specified, you will need to allow the AppID to access feed and then the default apikey will be assigned automatically. 180 | 181 | ```python 182 | data = {"field1":random.randint(1, 10),"field2":random.randint(1, 10),"field3":random.randint(1, 10)} 183 | microgear.writeFeed("myfeedid",data); 184 | microgear.writeFeed("myfeedid",data,"myapikey"); 185 | ``` 186 | 187 | **microgear.useTLS(tlsmode):** Enable or disable TLS. For microgear-python, TLS is disabled by default. 188 | 189 | arguments 190 | 191 | * *tlsmode* `boolean` - True or False 192 | 193 | ```python 194 | microgear.useTLS(True); 195 | ``` 196 | 197 | **microgear.pushOwner(*message*):** push notification to NETPIE mobile application 198 | 199 | arguments 200 | 201 | * *message* `string` – message to be sent 202 | 203 | 204 | ```python 205 | microgear.pushOwner("temp : 28.5"); 206 | ``` 207 | 208 | 209 | 210 | ### Event 211 | --------------- 212 | An application that runs on a microgear is an event-driven type, which responses to various events with the callback function in a form of event function call: 213 | 214 | 215 | **microgear.on_connect** This event is created when the microgear library successfully connects to the NETPIE platform. 216 | 217 | Parameter set 218 | 219 | * *callback* `function` - A function to execute after getting connected 220 | 221 | 222 | ```python 223 | def callback_connect() : 224 | print "Now I am connected with netpie" 225 | microgear.on_ connect = callback_connect 226 | ``` 227 | 228 | 229 | 230 | 231 | **microgear.on_disconnect** This event is created when the microgear library disconnects the NETPIE platform. 232 | 233 | Parameter set 234 | 235 | 236 | * *callback* `function` - A function to execute after getting disconnected 237 | 238 | 239 | ```python 240 | def callback_disconnect() : 241 | print "Disconnected” 242 | microgear.on_disconnect = callback_disconnect 243 | 244 | ``` 245 | 246 | 247 | 248 | 249 | **microgear.on_message** When there is an incomming message from chat or from subscribed topic. This event is created with the related information to be sent via the callback function. 250 | 251 | Parameter set 252 | * *callback* `function` - A function to execute after getting a message. It takes 2 arguments. 253 | * *topic* - The subscribed topic that he message belongs to. 254 | * *message* - The received message. 255 | 256 | 257 | ```python 258 | def callback_message(topic, message) : 259 | print "I got message from ", topic, ": ", message 260 | microgear.on_message= callback_message 261 | 262 | ``` 263 | 264 | 265 | **microgear.on_present** This event is created when there is a microgear under the same appid appears online to connect to NETPIE. 266 | 267 | Parameter set 268 | 269 | 270 | * *callback* `function` - A function to executed after this event. It takes 1 argument. 271 | * *gearkey* - The gearkey related to this event. 272 | 273 | 274 | ```python 275 | def callback_present(gearkey) : 276 | print gearkey+" become online." 277 | microgear.on_present = callback_present 278 | 279 | ``` 280 | 281 | 282 | 283 | 284 | **microgear.on_absent** This event is created when the microgear under the same appid appears offline. 285 | 286 | Parameter set 287 | 288 | 289 | * *callback* `function` - A function to executed after this event. It takes 1 argument. 290 | * *gearkey* - The gearkey related to this event. 291 | 292 | 293 | ```python 294 | def callback_absent(gearkey) : 295 | print gearkey+" become offline." 296 | microgear.on_absent = callback_absent 297 | 298 | ``` 299 | 300 | **microgear.on_warning** This event is created when some event occurs, and a warning message will be notified. 301 | 302 | Parameter set 303 | 304 | 305 | * *callback* `function` - A function to executed after this event. It takes 1 argument. 306 | * *msg* - A message related to this event. 307 | 308 | 309 | ```python 310 | def callback_warning(msg) : 311 | print msg 312 | microgear.on_warning = callback_warning 313 | 314 | ``` 315 | 316 | **microgear.on_info** This event is created when there is some event occurs within a microgear 317 | 318 | Parameter set 319 | 320 | 321 | * *callback* `function` - A function to executed after this event. It takes 1 argument. 322 | * *msg* - A message related to this event. 323 | 324 | 325 | ```python 326 | def callback_info(msg) : 327 | print msg 328 | microgear.on_info = callback_info 329 | 330 | ``` 331 | 332 | **microgear.on_error** This event is created when an error occurs within a microgear. 333 | 334 | Parameter set 335 | 336 | 337 | * *callback* `function` - A function to executed after this event. It takes 1 argument. 338 | * *msg* - An error message related to this event. 339 | 340 | 341 | ```python 342 | def callback_error(msg) : 343 | print msg 344 | microgear.on_error = callback_error 345 | 346 | ``` 347 | -------------------------------------------------------------------------------- /README.th.md: -------------------------------------------------------------------------------- 1 | # Microgear-python 2 | ----------- 3 | microgear- python คือ client library ภาษา Python ที่ทำหน้าที่เป็นตัวกลางในการเชื่อมโยง application code หรือ hardware เข้ากับบริการของ netpie platform เพื่อการพัฒนา IOT application รายละเอียดเกี่ยวกับ netpie platform สามารถศึกษาได้จาก http://netpie.io 4 | 5 | 6 | 7 | ## Port ที่มีการใช้งาน 8 | ----------- 9 | หากพบปัญหาการใช้งาน กรุณาตรวจสอบว่า port ต่อไปนี้ได้รับอนุญาตให้เข้าถึง 10 | - Non-TLS mode : 8080 and 1883 (microgear-python ใช้ mode นี้เป็นค่าเริ่มต้น) 11 | - TLS mode : 8081 and 8883 12 | 13 | 14 | 15 | ## การติดตั้ง 16 | ----------- 17 | ```sh 18 | $ pip install microgear 19 | ``` 20 | 21 | 22 | ## ตัวอย่างการเรียกใช้งาน 23 | ----------- 24 | ```python 25 | import microgear.client as microgear 26 | import logging 27 | import time 28 | 29 | appid = 30 | gearkey = 31 | gearsecret = 32 | 33 | microgear.create(gearkey,gearsecret,appid,{'debugmode': True}) 34 | 35 | def connection(): 36 | logging.info("Now I am connected with netpie") 37 | 38 | def subscription(topic,message): 39 | logging.info(topic+" "+message) 40 | 41 | def disconnect(): 42 | logging.info("disconnected") 43 | 44 | microgear.setalias("doraemon") 45 | microgear.on_connect = connection 46 | microgear.on_message = subscription 47 | microgear.on_disconnect = disconnect 48 | microgear.subscribe("/mails") 49 | microgear.connect(True) 50 | 51 | ``` 52 | [ตัวอย่างเพิ่มเติม](https://github.com/netpieio/microgear-python/wiki#%E0%B8%95%E0%B8%B1%E0%B8%A7%E0%B8%AD%E0%B8%A2%E0%B9%88%E0%B8%B2%E0%B8%87%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B9%83%E0%B8%8A%E0%B9%89%E0%B8%87%E0%B8%B2%E0%B8%99) 53 | 54 | 55 | ## การใช้งาน library 56 | ------------ 57 | ### Microgear 58 | --------------- 59 | **microgear.create(*gearkey*,*gearsecret*,*appid*,*args*):** 60 | 61 | arguments 62 | 63 | * *gearkey* `string` - เป็น key สำหรับ gear ที่จะรัน ใช้ในการอ้างอิงตัวตนของ gear 64 | * *gearsecret* `string` - เป็น secret ของ key ซึ่งจะใช้ประกอบในกระบวนการยืนยันตัวตน 65 | * *appid* `string` - กลุ่มของ application ที่ microgear จะทำการเชื่อมต่อ 66 | * *args* `dictionary` - เป็นการตั้งค่าเพิ่มเติม สำหรับ microgear ได้แก่ 67 | * *debugmode* `boolean` - แสดงข้อความในโหมด debug 68 | * *scope* `string` - กำหนด scope ให้กับ microgear เพื่อให้/จำกัดสิทธิ์บางอย่าง โดยมีรูปแบบดังนี้ 69 | * [r][w]:</topic/path> - r และ w คือสิทธิ์ในการ publish ละ subscribe topic ดังที่ระบุ เช่น rw:/outdoor/temp 70 | * name:<gearname> - คือสิทธิ์ในการตั้งชื่อตัวเองว่า <gearname> 71 | * chat:<gearname> - คือสิทธ์ในการ chat กับ <gearname> 72 | * *alias* string - กำหนดชื่อเรียกสำหรับ microgear นี้ โดยจะปรากฎที่หน้า key management และสามารถเป็นชื่อที่ microgear ตัวอื่นใช้สำหรับ `chat()` ได้ 73 | 74 | ในขั้นตอนของการสร้าง key บนเว็บ netpie.io นักพัฒนาสามารถกำหนดสิทธิ์ขั้นพื้นฐานให้แต่ละ key ได้อยู่แล้ว หากการ create microgear อยู่ภายใต้ขอบเขตของสิทธิ์ที่มี token จะถูกจ่ายอัตโนมัติ และ microgear จะสามารถเชื่อมต่อ netpie platform ได้ทันที แต่หาก scope ที่ร้องขอนั้นมากเกินกว่าสิทธิ์ที่กำหนดไว้ นักพัฒนาจะได้รับ notification ให้พิจารณาอนุมัติ microgear ที่เข้ามาขอเชื่อมต่อ ข้อควรระวัง หาก microgear มีการกระทำการเกินกว่าสิทธิ์ที่ได้รับไป เช่น พยายามจะ publish ไปยัง topic ที่ตัวเองไม่มีสิทธิ์ netpie จะตัดการเชื่อมต่อของ microgear โดยอัตโนมัติ ในกรณีที่ใช้ APPKEY เป็น gearkey เราสามารถละเว้น attribute นี้ได้ เพราะ APPKEY จะได้สิทธิ์ทุกอย่างในฐานะของเจ้าของ app โดย default อยู่แล้ว 75 | 76 | 77 | ```python 78 | gearkey = 79 | gearsecret = 80 | appid = 81 | 82 | microgear.create(gearkey,gearsecret,appid, {'debugmode': True, 'scope': "r:/outdoor/temp,w:/outdoor/valve,name:logger,chat:plant", 'alias': "logger"}) 83 | ``` 84 | 85 | 86 | 87 | 88 | **microgear.connect(*will_block*):** การเชื่อมต่อ microgear 89 | 90 | argument 91 | 92 | * *will_block* `boolean` - `(optional)` ระบุรูปแบบการเชื่อมต่อ ว่าให้มีการ Block หลังจากเรียกฟังก์ชั่น หรือไม่ ซึ่งจะมีค่า default เป็น `False` โดยโปรแกรมจะทำงานในบรรทัดถัดไปหลังจากที่ทำการ connect แล้ว ซึ่งจะทำให้ ผู้พัฒนาสามารถ เขียนโปรแกรม ในการติดต่อกับ platfrom ต่อไปได้ โดยการเชื่อมต่อกับ platform จะคงอยู่ เท่าที่มีการทำงานของโปรแกรม เช่น 93 | 94 | ```python 95 | microgear.connect() 96 | while True: 97 | microgear.chat("doraemon","Hello world. "+str(int(time.time()))) 98 | time.sleep(2) 99 | ``` 100 | หากต้องการให้ library ทำการ Block หลังจากทำการ connect แล้ว ซึ่งหลังจาก connect แล้วโปรแกรมหยุดอยู่ที่การทำงานร่วมกับ platform โดยจะทำงานตามที่มี เหตุการณ์ callback (on_*) ที่ถูกกำหนดไว้ก่อนหน้า โดยสามารถระบุ พารามิเตอร์เป็น `True` ได้ เช่น 101 | ```python 102 | microgear.connect(True) 103 | ``` 104 | 105 | 106 | 107 | 108 | **microgear.setalias(*alias*):** กำหนดชื่อเรียกสำหรับ microgear นี้ โดยจะปรากฎที่หน้า key management และสามารถเป็นชื่อที่ microgear ตัวอื่นใช้สำหรับ `chat()` ได้ 109 | 110 | argument 111 | 112 | * *alias* `string` - ชื่อของ microgear นี้ 113 | 114 | 115 | 116 | ```python 117 | microgear.setalias("python"); 118 | ``` 119 | 120 | **microgear.setname(*gearname*):** microgear สามารถตั้งชื่อตัวเองได้ 121 | ซึ่งสามารถใช้เป็นชื่อเรียกในการใช้ฟังก์ชั่น chat() **แนะนำให้ใช้ `setalias()` แทน** 122 | 123 | argument 124 | 125 | * *gearname* `string` - ชื่อของ microgear นี้ 126 | 127 | 128 | 129 | ```python 130 | microgear.setname("python"); 131 | ``` 132 | 133 | **microgear.chat(*gearname*, *message*):** การส่งข้อความโดยระบุ gearname และข้อความที่ต้องการส่ง 134 | 135 | arguments 136 | 137 | * *gearname* `string` - ชื่อของ microgear นี้ 138 | * *message* `string` – ข้อความ 139 | 140 | ```python 141 | microgear.chat("html","hello from python"); 142 | ``` 143 | 144 | 145 | 146 | **microgear.publish(*topic*, *message*, *retain*):** ในกรณีที่ต้องการส่งข้อความแบบไม่เจาะจงผู้รับ สามารถใช้ฟังชั่น publish ไปยัง topic ที่กำหนดได้ ซึ่งจะมีแต่ microgear ที่ subscribe topoic นี้เท่านั้น ที่จะได้รับข้อความ 147 | 148 | arguments 149 | 150 | * *topic* `string` - ชื่อของ topic ที่ต้องการจะส่งข้อความไปถึง 151 | * *message* `string` – ข้อความ 152 | * *args* `dictionary` - เป็นการตั้งค่าเพิ่มเติม สำหรับการ publish ได้แก่ 153 | * *retain* `boolean` - ระบุค่า `True` ถ้าต้องการเก็บข้อความไว้ หากมีการ subscribe topic นี้ก็จะได้รับข้อความนี้อีก ค่าปริยายเป็น `False` หากไม่ระบุ และถ้าต้องการลบข้อความที่บันทึกไว้ให้ส่งข้อความ "" ซึ่งมีความยาวเป็น 0 เพื่อล้างค่าข้อความที่ไว้ทึกไว้ 154 | 155 | ```python 156 | microgear.publish("/outdoor/temp","28.5"); 157 | microgear.publish("/outdoor/temp","28.5",{'retain':True}); 158 | ``` 159 | 160 | 161 | 162 | **microgear.subscribe(*topic*)** microgear อาจจะมีความสนใจใน topic 163 | ใดเป็นการเฉพาะ เราสามารถใช้ฟังก์ชั่น subscribe() ในการบอกรับ message ของ topic นั้นได้ 164 | 165 | argument 166 | 167 | * *topic* `string` - ชื่อของ topic ที่ความสนใจ โดยขึ้นต้นด้วยเครื่องหมาย "/" 168 | 169 | 170 | 171 | ```python 172 | microgear.subscribe("/temp"); 173 | ``` 174 | 175 | **microgear.resettoken()** สำหรับต้องการลบ Token ที่มีอยู่ ซึ่งจะทำการลบ Token ที่อยู่ภายใน cache และบน platform เมื่อลบแล้ว จำเป็นจะต้องขอ Token ใหม่ทุกครั้ง 176 | 177 | ```python 178 | microgear.resettoken(); 179 | ``` 180 | 181 | **microgear.writeFeed(*feedid*, *data*, *apikey*):** เขียนข้อมูลลง feed storage 182 | 183 | arguments 184 | 185 | * *feedid* `string` - ชื่อของ feed ที่ต้องการจะเขียนข้อมูล 186 | * *data* `dict` – ข้อมูลที่จะบันทึก ในรูปแบบ json 187 | * *apikey* `string` - apikey สำหรับตรวจสอบสิทธิ์ หากไม่กำหนด จะใช้ default apikey ของ feed ที่ให้สิทธิ์ไว้กับ AppID 188 | 189 | ```python 190 | data = {"field1":random.randint(1, 10),"field2":random.randint(1, 10),"field3":random.randint(1, 10)} 191 | microgear.writeFeed("myfeedid",data); 192 | microgear.writeFeed("myfeedid",data,"myapikey"); 193 | ``` 194 | 195 | **microgear.useTLS (tlsmode):** เลือกใช้หรือไม่ใช้การเข้ารหัสแบบ TLS. หากกไม่ได้เซตอะไร โดยค่าเริ่มต้น microgear-python จะไม่ใช้ TLS 196 | 197 | arguments 198 | * *tlsmode* `boolean` - `True คือใช้ TLS` 199 | 200 | ```python 201 | microgear.useTLS(false); 202 | ``` 203 | 204 | **microgear.pushOwner(*message*):** ส่งการแจ้งเตือน ไปยัง NETPIE mobile application 205 | 206 | arguments 207 | 208 | * *message* `string` – ข้อความ 209 | 210 | 211 | ```python 212 | microgear.pushOwner("temp : 28.5"); 213 | ``` 214 | 215 | 216 | 217 | ### Event 218 | --------------- 219 | application ที่รันบน microgear จะมีการทำงานในแบบ event driven คือเป็นการทำงานตอบสนองต่อ event ต่างๆ ด้วยการเขียน callback function ขึ้นมารองรับในลักษณะๆดังต่อไปนี้ 220 | 221 | **microgear.on_connect** เกิดขึ้นเมื่อ microgear library เชื่อมต่อกับ platform สำเร็จ 222 | 223 | ค่าที่ set 224 | 225 | * *callback* `function` - ฟังก์ชั่นที่จะทำงาน เมื่อมีการ connect 226 | 227 | 228 | ```python 229 | def callback_connect() : 230 | print "Now I am connected with netpie" 231 | microgear.on_ connect = callback_connect 232 | ``` 233 | 234 | 235 | 236 | 237 | **microgear.on_disconnect** เกิดขึ้นเมื่อ microgear library ตัดการเชื่อมต่อกับ platform 238 | 239 | ค่าที่ set 240 | 241 | 242 | * *callback* `function` - callback function 243 | 244 | 245 | ```python 246 | def callback_disconnect() : 247 | print "Disconnected” 248 | microgear.on_disconnect = callback_disconnect 249 | 250 | ``` 251 | 252 | 253 | 254 | 255 | **microgear.on_message** เกิดขึ้นเมื่อ ได้รับข้อความจากการ chat หรือ หัวข้อที่ subscribe 256 | 257 | ค่าที่ set 258 | * *callback* `function` - ฟังก์ชั่น ที่จะทำงานเมื่อได้รับข้อความ โดยฟังก์ชั่นนี้จะรับ parameter 2 ตัวคือ 259 | * *topic* - ชื่อ topic ที่ได้รับข้อความนี้ 260 | * *message* - ข้อความที่ได้รับ 261 | 262 | 263 | ```python 264 | def callback_message(topic, message) : 265 | print "I got message from ", topic, ": ", message 266 | microgear.on_message= callback_message 267 | 268 | ``` 269 | 270 | 271 | **microgear.on_present** event นี้จะเกิดขึ้นเมื่อมี microgear ใน appid เดียวกัน online เข้ามาเชื่อมต่อ netpie 272 | 273 | ค่าที่ set 274 | 275 | 276 | * *callback* `function` - จะทำงานเมื่อเกิดเหตุการณ์นี้ โดยจะรับค่า parameter คือ 277 | * *gearkey* - ระบุค่าของ gearkey ที่เกี่ยวข้องกับเหตุการณ์นี้ 278 | 279 | 280 | ```python 281 | def callback_present(gearkey) : 282 | print gearkey+" become online." 283 | microgear.on_present = callback_present 284 | 285 | ``` 286 | 287 | 288 | 289 | 290 | **microgear.on_present** event นี้จะเกิดขึ้นเมื่อมี microgear ใน appid เดียวกัน offline หายไป 291 | 292 | ค่าที่ set 293 | 294 | 295 | * *callback* `function` - จะทำงานเมื่อเกิดเหตุการณ์นี้ โดยจะรับค่า parameter คือ 296 | * *gearkey* - ระบุค่าของ gearkey ที่เกี่ยวข้องกับเหตุการณ์นี้ 297 | 298 | 299 | ```python 300 | def callback_absent(gearkey) : 301 | print gearkey+" become offline." 302 | microgear.on_absent = callback_absent 303 | 304 | ``` 305 | 306 | **microgear.on_warning** เป็น event ที่เกิดมีเหตุการณ์บางอย่างเกิดขึ้นขึ้น และมีการเตือนให้ทราบ 307 | 308 | ค่าที่ set 309 | 310 | 311 | * *callback* `function` - จะทำงานเมื่อเกิดเหตุการณ์นี้ โดยจะรับค่า parameter คือ 312 | * *msg* - ระบุข้อความ ที่เกี่ยวข้องกับเหตุการณ์นี้ 313 | 314 | 315 | ```python 316 | def callback_warning(msg) : 317 | print msg 318 | microgear.on_warning = callback_warning 319 | 320 | ``` 321 | 322 | **microgear.on_info** เป็น event ที่เกิดมีเหตุการณ์บางอย่างเกิดขึ้นขึ้นภายใน microgear 323 | 324 | ค่าที่ set 325 | 326 | 327 | * *callback* `function` - จะทำงานเมื่อเกิดเหตุการณ์นี้ โดยจะรับค่า parameter คือ 328 | * *msg* - ระบุข้อความ ที่เกี่ยวข้องกับเหตุการณ์นี้ 329 | 330 | 331 | ```python 332 | def callback_info(msg) : 333 | print msg 334 | microgear.on_info = callback_info 335 | 336 | ``` 337 | 338 | **microgear.on_error** event นี้จะเกิดขึ้นเมื่อมี error 339 | 340 | ค่าที่ set 341 | 342 | 343 | * *callback* `function` - จะทำงานเมื่อเกิดเหตุการณ์นี้ โดยจะรับค่า parameter คือ 344 | * *msg* - ระบุ error ที่เกี่ยวข้องกับเหตุการณ์นี้ 345 | 346 | 347 | ```python 348 | def callback_error(msg) : 349 | print msg 350 | microgear.on_error = callback_error 351 | 352 | ``` 353 | -------------------------------------------------------------------------------- /examples/basic.py: -------------------------------------------------------------------------------- 1 | import microgear.client as microgear 2 | import time 3 | import logging 4 | 5 | appid = 6 | gearkey = 7 | gearsecret = 8 | 9 | microgear.create(gearkey,gearsecret,appid,{'debugmode': True}) 10 | 11 | def connection(): 12 | logging.info("Now I am connected with netpie") 13 | 14 | def subscription(topic,message): 15 | logging.info(topic+" "+message) 16 | 17 | def disconnect(): 18 | logging.debug("disconnect is work") 19 | 20 | microgear.setalias("doraemon") 21 | microgear.on_connect = connection 22 | microgear.on_message = subscription 23 | microgear.on_disconnect = disconnect 24 | microgear.subscribe("/mails") 25 | microgear.connect(False) 26 | 27 | while True: 28 | if(microgear.connected): 29 | microgear.chat("doraemon","Hello world."+str(int(time.time()))) 30 | time.sleep(3) 31 | -------------------------------------------------------------------------------- /microgear/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | __version__ = '1.2.7' 3 | 4 | gearauthsite = "ga.netpie.io" 5 | gearapiport = '8080'; 6 | gearapisecureport = '8081'; 7 | gbport = '1883'; 8 | gbsport = '8883'; 9 | 10 | mgrev = "PY11k" 11 | gearkey = None 12 | gearsecret = None 13 | gearalias = None 14 | appid = None 15 | gearname = None 16 | accesstoken = None 17 | requesttoken = None 18 | client = None 19 | scope = "" 20 | gearexaddress = None 21 | gearexport = None 22 | mqtt_client = None 23 | logger = logging.getLogger("python-microgear") 24 | securemode = False 25 | state = False 26 | -------------------------------------------------------------------------------- /microgear/cache.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import sys 4 | 5 | 6 | CURRENT_DIR = os.path.abspath(os.path.dirname(sys.argv[0])) 7 | 8 | 9 | def get_item(key): 10 | """Return content in cached file in JSON format""" 11 | CACHED_KEY_FILE = os.path.join(CURRENT_DIR, key) 12 | 13 | try: 14 | return json.loads(open(CACHED_KEY_FILE, "rb").read().decode('UTF-8'))["_"] 15 | except (IOError, ValueError): 16 | return None 17 | 18 | 19 | def set_item(key,value): 20 | """Write JSON content from value argument to cached file and return""" 21 | CACHED_KEY_FILE = os.path.join(CURRENT_DIR, key) 22 | 23 | open(CACHED_KEY_FILE, "wb").write(json.dumps({"_": value}).encode('UTF-8')) 24 | 25 | return value 26 | 27 | 28 | def delete_item(key): 29 | """Delete cached file if present""" 30 | CACHED_KEY_FILE = os.path.join(CURRENT_DIR, key) 31 | 32 | if os.path.isfile(CACHED_KEY_FILE): 33 | os.remove(CACHED_KEY_FILE) 34 | 35 | -------------------------------------------------------------------------------- /microgear/client.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import json 3 | import microgear 4 | from microgear import cache 5 | import time 6 | import re 7 | import paho.mqtt.client as mqtt 8 | import threading 9 | import os 10 | import sys 11 | import requests 12 | import certifi 13 | 14 | def do_nothing(arg1=None, arg2=None): 15 | pass 16 | 17 | subscribe_list = [] 18 | current_subscribe_list = [] 19 | current_id = None 20 | publish_list = [] 21 | block_loop = False 22 | 23 | on_present = do_nothing 24 | on_absent = do_nothing 25 | on_connect = do_nothing 26 | on_message = do_nothing 27 | on_error = do_nothing 28 | on_warning = do_nothing 29 | on_info = do_nothing 30 | on_disconnect = do_nothing 31 | config_list = {} 32 | 33 | def create(gearkey,gearsecret, appid="", args = {}): 34 | if 'debugmode' in args: 35 | logging.basicConfig(level=logging.INFO, 36 | format='%(asctime)s %(levelname)-8s %(message)s', 37 | datefmt='%d/%m/%Y %I:%M:%S %p', 38 | ) 39 | else: 40 | logging.basicConfig(level=logging.WARNING, 41 | format='%(asctime)s %(levelname)-8s %(message)s', 42 | datefmt='%d/%m/%Y %I:%M:%S %p', 43 | ) 44 | microgear.gearalias = args.get('alias',"")[0:16] 45 | if 'scope' in args: 46 | matchScope = re.match( r'^(\w+:[a-zA-Z\/]+,*)+$', args['scope']) 47 | if matchScope: 48 | microgear.scope = args["scope"] 49 | else: 50 | microgear.scope = "" 51 | logging.warning("Specify scope is not valid") 52 | 53 | microgear.gearkey = gearkey 54 | microgear.gearsecret = gearsecret 55 | microgear.appid = appid 56 | 57 | def client_on_connect(client, userdata, rc): 58 | global block 59 | microgear.state = True 60 | logging.info("Connected with result code "+str(rc)) 61 | if rc == 0 : 62 | on_connect() 63 | auto_subscribeAndpublish() 64 | elif rc == 1 : 65 | logging.warning("Unable to connect: Incorrect protocol version.") 66 | elif rc == 2 : 67 | logging.warning("Unable to connect: Invalid client identifier.") 68 | elif rc == 3 : 69 | logging.warning("Unable to connect: Server unavailable.") 70 | elif rc == 4 : 71 | unsubscribe(current_id) 72 | microgear.mqtt_client.disconnect() 73 | on_info("Invalid credential.") 74 | logging.info("Unable to connect: Invalid credential, requesting new one") 75 | resettoken() 76 | connect(block_loop) 77 | elif rc == 5 : 78 | on_warning("Not authorised.") 79 | logging.warning("Unable to connect: Not authorised.") 80 | else: 81 | logging.warning("Unable to connect: Unknown reason") 82 | 83 | def client_on_publish(client, userdata, mid): 84 | #Publish callback 85 | pass 86 | 87 | def client_on_message(client, userdata, msg): 88 | topics = msg.topic.split("/") 89 | if msg.topic != "@info" and msg.topic != "@error": 90 | if topics[2] == "&present": 91 | on_present(str(msg.payload)) 92 | elif topics[2] == "&absent": 93 | on_absent(str(msg.payload)) 94 | elif '&id' in topics[2]: 95 | #controll message 96 | pass 97 | else: 98 | on_message(msg.topic,str(msg.payload)) 99 | elif msg.topic == "@info": 100 | on_info(str(msg.payload)) 101 | elif msg.topic == "@error": 102 | on_error(str(msg.payload)) 103 | 104 | def client_on_subscribe(client, userdata, mid, granted_qos): 105 | ## TODO: Check subscribe fail 106 | pass 107 | 108 | def client_on_disconnect(client, userdata, rc): 109 | if rc!=0: 110 | microgear.state = False 111 | on_disconnect() 112 | logging.info("Diconnected with result code "+str(rc)) 113 | 114 | def connect(block=False): 115 | global block_loop 116 | block_loop = block 117 | global current_subscribe_list 118 | global current_id 119 | times = 1 120 | while not microgear.accesstoken: 121 | get_token() 122 | time.sleep(times) 123 | times = times+10 124 | microgear.mqtt_client = mqtt.Client(microgear.accesstoken["token"]) 125 | current_id = '/&id/'+str(microgear.accesstoken["token"])+'/#' 126 | current_subscribe_list.append('/&id/'+str(microgear.accesstoken["token"])+'/#') 127 | endpoint = microgear.accesstoken["endpoint"].split("//")[1].split(":") 128 | username = microgear.gearkey+"%"+str(int(time.time())) 129 | password = hmac(microgear.accesstoken["secret"]+"&"+microgear.gearsecret,microgear.accesstoken["token"]+"%"+username) 130 | microgear.mqtt_client.username_pw_set(username,password) 131 | if microgear.securemode: 132 | microgear.mqtt_client.tls_set(certifi.where()) 133 | microgear.mqtt_client.connect(endpoint[0],int(microgear.gbsport), 60) 134 | else: 135 | microgear.mqtt_client.connect(endpoint[0],int(microgear.gbport), 60) 136 | microgear.mqtt_client.on_connect = client_on_connect 137 | microgear.mqtt_client.on_message = client_on_message 138 | microgear.mqtt_client.on_publish = client_on_publish 139 | microgear.mqtt_client.on_subscribe = client_on_subscribe 140 | microgear.mqtt_client.on_disconnect = client_on_disconnect 141 | 142 | if(block): 143 | microgear.mqtt_client.loop_forever() 144 | else: 145 | microgear.mqtt_client.loop_start() 146 | while True: 147 | time.sleep(2) 148 | break 149 | 150 | def auto_subscribeAndpublish(): 151 | global publish_list 152 | global current_subscribe_list 153 | if microgear.mqtt_client: 154 | microgear.mqtt_client.subscribe("/"+microgear.appid+"/&present") 155 | microgear.mqtt_client.subscribe("/"+microgear.appid+"/&absent") 156 | for topic in current_subscribe_list : 157 | microgear.mqtt_client.subscribe(topic) 158 | logging.info("Auto subscribe "+topic) 159 | else: 160 | on_error("Microgear currently is not available.") 161 | logging.error("Microgear currently is not available.") 162 | 163 | if microgear.mqtt_client : 164 | for topic in publish_list : 165 | microgear.mqtt_client.publish(topic[0],topic[1],retain=topic[2].get('retain',False)) 166 | publish_list = [] 167 | else: 168 | on_error("Microgear currently is not available.") 169 | logging.error("Microgear currently is not available.") 170 | 171 | def subscribe_thread(topic,qos=0): 172 | if microgear.mqtt_client : 173 | logging.info("Auto subscribe "+topic) 174 | microgear.mqtt_client.subscribe(topic,qos) 175 | else: 176 | on_error("Microgear currently is not available.") 177 | logging.error("Microgear currently is not available.") 178 | 179 | def subscribe(topic,qos=0): 180 | global subscribe_list 181 | global current_subscribe_list 182 | threads = [] 183 | if "/"+microgear.appid+topic not in current_subscribe_list: 184 | current_subscribe_list.append("/"+microgear.appid+topic) 185 | 186 | if microgear.mqtt_client: 187 | t = threading.Thread(target=subscribe_thread, args=("/"+microgear.appid+topic,qos)) 188 | threads.append(t) 189 | t.start() 190 | else: 191 | subscribe_list.append("/"+microgear.appid+topic) 192 | 193 | def unsubscribe(topic): 194 | global current_subscribe_list 195 | global current_id 196 | if microgear.mqtt_client: 197 | if topic == current_id: 198 | current_subscribe_list.remove(current_id) 199 | microgear.mqtt_client.unsubscribe(current_id) 200 | if "/"+microgear.appid+topic in current_subscribe_list: 201 | current_subscribe_list.remove("/"+microgear.appid+topic) 202 | microgear.mqtt_client.unsubscribe("/"+microgear.appid+topic) 203 | logging.info("Auto unsubscribe "+topic) 204 | else: 205 | on_error("Microgear currently is not available.") 206 | logging.error("Microgear currently is not available.") 207 | 208 | def publish_thread(topic,message,args = {}): 209 | qos = 0 210 | retain = False 211 | 212 | if 'qos' in args: 213 | gos = args['qos'] 214 | 215 | if 'retain' in args: 216 | retain = args['retain'] 217 | 218 | if microgear.mqtt_client : 219 | microgear.mqtt_client.publish(topic,message,qos=qos,retain=retain) 220 | else: 221 | on_error("Microgear currently is not available.") 222 | logging.error("Microgear currently is not available.") 223 | 224 | def publish(topic,message,args = {}): 225 | global publish_list 226 | threads = [] 227 | if microgear.mqtt_client: 228 | t = threading.Thread(target=publish_thread, args=("/"+microgear.appid+topic,message,args)) 229 | threads.append(t) 230 | t.start() 231 | else: 232 | publish_list.append(["/"+microgear.appid+topic,message,args]) 233 | 234 | def setname(topic): 235 | logging.warning("Deprecated soon: Please consider using setalias()") 236 | microgear.gearname = topic 237 | subscribe("/gearname/"+topic) 238 | 239 | def setalias(alias): 240 | publish("/@setalias/"+alias,"") 241 | 242 | def chat(topic,message): 243 | publish("/gearname/"+topic,message) 244 | 245 | def readstream(stream, filter): 246 | publish('/@readstream/'+stream,'{"filter":"'+filter+'"}') 247 | 248 | def writestream(stream,data): 249 | publish('/@writestream/'+stream,'{"data":'+data+'}') 250 | 251 | def pushOwner(message): 252 | if type(message) is dict: 253 | logging.info("push notification json") 254 | json = "{" 255 | for key in message: 256 | json += "\""+str(key)+"\""+":"+str(message[key])+"," 257 | json = json[:len(json)-1] + "}" 258 | publish("/@push/owner",json) 259 | else: 260 | logging.info("push notification message") 261 | publish("/@push/owner",message) 262 | 263 | def get_token(): 264 | logging.info("Check stored token.") 265 | cached = cache.get_item("microgear-"+microgear.gearkey+".cache") 266 | if cached: 267 | if cached.get("accesstoken"): 268 | if not cached.get("key"): 269 | cached["key"] = microgear.gearkey 270 | cache.set_item("microgear-"+microgear.gearkey+".cache", cached) 271 | microgear.accesstoken = cached.get("accesstoken") 272 | for name,value in microgear.accesstoken.items(): 273 | microgear.accesstoken[name] = str(value) 274 | endpoint = microgear.accesstoken.get("endpoint").split("//")[1].split(":") 275 | microgear.gearexaddress = endpoint[0] 276 | microgear.gearexport = endpoint[1] 277 | elif cached.get("requesttoken"): 278 | get_accesstoken(cached) 279 | else: 280 | get_requesttoken(cached) 281 | else: 282 | cached = cache.set_item("microgear-"+microgear.gearkey+".cache", {"key": microgear.gearkey}) 283 | 284 | def get_requesttoken(cached): 285 | logging.info("Requesting a request token.") 286 | path="" 287 | url="" 288 | if len(microgear.gearalias): 289 | verifier = microgear.gearalias 290 | path = '/oauth2/authorize?'+"response_type=code&client_id=" + microgear.gearkey + "&scope=appid:" + microgear.appid +" "+"alias:" +microgear.gearalias+ "&state=mgrev:" + microgear.mgrev; 291 | else: 292 | verifier = microgear.mgrev 293 | path = '/oauth2/authorize?'+"response_type=code&client_id=" + microgear.gearkey + "&scope=appid:" + microgear.appid +"&state=mgrev:" + microgear.mgrev; 294 | 295 | if microgear.securemode: 296 | url = "https://"+microgear.gearauthsite+":"+microgear.gearapisecureport+path; 297 | else: 298 | url = "http://"+microgear.gearauthsite+":"+microgear.gearapiport+path; 299 | response = requests.get(url) 300 | response = response.url.split("code=") 301 | if len(response)==2: 302 | cached["requesttoken"] = {"token": response[1],"secret": None,"verifier": verifier} 303 | cache.set_item("microgear-"+microgear.gearkey+".cache", cached) 304 | microgear.requesttoken = cached["requesttoken"] 305 | get_accesstoken(cached) 306 | else: 307 | on_error("Request token is not issued, please check your appkey and appsecret.") 308 | logging.error("Request token is not issued, please check your appkey and appsecret.") 309 | 310 | def get_accesstoken(cached): 311 | microgear.requesttoken = cached.get("requesttoken") 312 | logging.info("Already has request token.") 313 | logging.info("Requesting an access token.") 314 | verifier = "" 315 | url = "" 316 | path = "/oauth2/token?grant_type=authorization_code&code=" + microgear.requesttoken.get("token") + "&client_id=" + microgear.gearkey + "&client_secret=" + microgear.gearsecret + "&state=mgrev:" + microgear.mgrev; 317 | if microgear.securemode: 318 | url = "https://"+microgear.gearauthsite+":"+microgear.gearapisecureport+path; 319 | else: 320 | url = "http://"+microgear.gearauthsite+":"+microgear.gearapiport+path; 321 | response = requests.post(url) 322 | if response.status_code==200: 323 | datajson = json.loads(response.text) 324 | token = datajson['access_token'].split(':') 325 | revokecode = hmac(token[1]+"&"+microgear.gearsecret,token[0]).replace('/','_') 326 | cached["requesttoken"] = None 327 | cached["accesstoken"] = { 328 | "token": token[0], 329 | "secret": token[1], 330 | "endpoint": datajson['endpoint'], 331 | "revokecode": revokecode 332 | } 333 | flag = datajson['flag'] 334 | if flag == "P": 335 | cache.set_item("microgear-"+microgear.gearkey+".cache", cached) 336 | elif flag == "S": 337 | cache.set_item("microgear-"+microgear.gearkey+".cache", {}) 338 | microgear.accesstoken = cached["accesstoken"] 339 | else: 340 | resettoken() 341 | on_error("Access token is not issued, please check your consumerkey and consumersecret.") 342 | logging.error("Access token is not issued, please check your consumerkey and consumersecret.") 343 | 344 | 345 | def hmac(key, message): 346 | import base64 347 | import hmac 348 | import hashlib 349 | 350 | hash = hmac.new(key.encode('utf-8'),message.encode('utf-8'), hashlib.sha1).digest() 351 | password = base64.encodestring(hash) 352 | password = password.strip() 353 | 354 | return password.decode('utf-8') 355 | 356 | def resettoken(): 357 | cached = cache.get_item("microgear-"+microgear.gearkey+".cache") 358 | if cached : 359 | microgear.accesstoken = cached.get("accesstoken",{}) 360 | if "revokecode" in microgear.accesstoken : 361 | path = "/api/revoke/"+microgear.accesstoken["token"]+"/"+microgear.accesstoken["revokecode"] 362 | url = "" 363 | if microgear.securemode: 364 | url = "https://"+microgear.gearauthsite+":"+microgear.gearapisecureport+path; 365 | else: 366 | url = "http://"+microgear.gearauthsite+":"+microgear.gearapiport+path; 367 | response = requests.get(url) 368 | if response.status_code==200: 369 | cache.delete_item("microgear-"+microgear.gearkey+".cache") 370 | else: 371 | on_error("Reset token error.") 372 | logging.error("Reset token error.") 373 | else: 374 | cache.delete_item("microgear-"+microgear.gearkey+".cache") 375 | logging.warning("Token is still, please check your key on Key Management.") 376 | microgear.accesstoken = None 377 | 378 | def disconnect(): 379 | microgear.mqtt_client.disconnect(); 380 | 381 | def writeFeed(feedid,data,feedkey=""): 382 | if len(feedid)>0 and type(data) is dict: 383 | json = "{" 384 | for key in data: 385 | json += "\""+str(key)+"\""+":"+str(data[key])+"," 386 | json = json[:len(json)-1] + "}" 387 | if feedkey == "": 388 | publish("/@writefeed/"+feedid,json) 389 | else: 390 | publish("/@writefeed/"+feedid+"/"+feedkey,json) 391 | logging.info(json) 392 | else: 393 | logging.info("Invalid parameters, please try again") 394 | 395 | def setConfig(key,value): 396 | if(key=="GEARAUTH"): 397 | config_list["GEARAUTH"] = value 398 | microgear.gearauthsite = value 399 | 400 | def getConfig(key): 401 | return config_list[key] 402 | 403 | def useTLS(boolean): 404 | microgear.securemode = boolean 405 | 406 | def connected(): 407 | return micrgear.state 408 | 409 | 410 | 411 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | setup( 3 | name = 'microgear', 4 | packages = ['microgear'], # this must be the same as the name above 5 | version = '1.2.7', 6 | description = 'Client library of Python, connect application code or hardware to netpie platform.', 7 | author = 'netpie', 8 | author_email = 'support@netpie.io', 9 | url = 'https://github.com/netpieio/microgear-python', # use the URL to the github repo 10 | keywords = ['netpie','iot','mqtt'], # arbitrary keywords 11 | classifiers = [], 12 | install_requires=['paho-mqtt==1.2.3','requests','certifi'], 13 | ) 14 | --------------------------------------------------------------------------------