| 1 |  |  | from __future__ import absolute_import | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | import json | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | import os | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | from ._connection import DatabaseConnection | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | from ._connectorobject import ConnectorObject | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | from ._datapointarray import DatapointArray | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  | class Device(ConnectorObject): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |     def create(self, public=False, **kwargs): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |         """Creates the device. Attempts to create private devices by default, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |         but if public is set to true, creates public devices. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |         You can also set other default properties by passing in the relevant information. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |         For example, setting a device with the given nickname and description:: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |             dev.create(nickname="mydevice", description="This is an example") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |         Furthermore, ConnectorDB supports creation of a device's streams immediately, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |         which can considerably speed up device setup:: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |             dev.create(streams={ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |                 "stream1": {"schema": '{\"type\":\"number\"}'} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |             }) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  |         Note that the schema must be encoded as a string when creating in this format. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |         kwargs["public"] = public | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |         self.metadata = self.db.create(self.path, kwargs).json() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |  | 
            
                                                                                                            
                            
            
                                                                    
                                                                                                        
            
            
                | 33 |  | View Code Duplication |     def streams(self): | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |         """Returns the list of streams that belong to the device""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |         result = self.db.read(self.path, {"q": "ls"}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |         if result is None or result.json() is None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |             return [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |         streams = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |         for s in result.json(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |             strm = self[s["name"]] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |             strm.metadata = s | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |             streams.append(strm) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |         return streams | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |     def __getitem__(self, stream_name): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |         """Gets the child stream by name""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |         return Stream(self.db, self.path + "/" + stream_name) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |     def __repr__(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |         """Returns a string representation of the device""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |         return "[Device:%s]" % (self.path, ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |     def export(self, directory): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |         """Exports the device to the given directory. The directory can't exist.  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |         You can later import this device by running import_device on a user. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |         if os.path.exists(directory): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |             raise FileExistsError( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |                 "The device export directory already exists") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |         os.mkdir(directory) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |         # Write the device's info | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |         with open(os.path.join(directory, "device.json"), "w") as f: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |             json.dump(self.data, f) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |         # Now export the streams one by one | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |         for s in self.streams(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |             s.export(os.path.join(directory, s.name)) | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 71 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 72 |  |  |     def import_stream(self, directory): | 
            
                                                                        
                            
            
                                    
            
            
                | 73 |  |  |         """Imports a stream from the given directory. You export the Stream | 
            
                                                                        
                            
            
                                    
            
            
                | 74 |  |  |         by using stream.export()""" | 
            
                                                                        
                            
            
                                    
            
            
                | 75 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 76 |  |  |         # read the stream's info | 
            
                                                                        
                            
            
                                    
            
            
                | 77 |  |  |         with open(os.path.join(directory, "stream.json"), "r") as f: | 
            
                                                                        
                            
            
                                    
            
            
                | 78 |  |  |             sdata = json.load(f) | 
            
                                                                        
                            
            
                                    
            
            
                | 79 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 80 |  |  |         s = self[sdata["name"]] | 
            
                                                                        
                            
            
                                    
            
            
                | 81 |  |  |         if s.exists(): | 
            
                                                                        
                            
            
                                    
            
            
                | 82 |  |  |             raise ValueError("The stream " + s.name + " already exists") | 
            
                                                                        
                            
            
                                    
            
            
                | 83 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 84 |  |  |         # Create the stream empty first, so we can insert all the data without | 
            
                                                                        
                            
            
                                    
            
            
                | 85 |  |  |         # worrying about schema violations or downlinks | 
            
                                                                        
                            
            
                                    
            
            
                | 86 |  |  |         s.create() | 
            
                                                                        
                            
            
                                    
            
            
                | 87 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 88 |  |  |         # Now, in order to insert data into this stream, we must be logged in as | 
            
                                                                        
                            
            
                                    
            
            
                | 89 |  |  |         # the owning device | 
            
                                                                        
                            
            
                                    
            
            
                | 90 |  |  |         ddb = DatabaseConnection(self.apikey, url=self.db.baseurl) | 
            
                                                                        
                            
            
                                    
            
            
                | 91 |  |  |         d = Device(ddb, self.path) | 
            
                                                                        
                            
            
                                    
            
            
                | 92 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 93 |  |  |         # Set up the owning device | 
            
                                                                        
                            
            
                                    
            
            
                | 94 |  |  |         sown = d[s.name] | 
            
                                                                        
                            
            
                                    
            
            
                | 95 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 96 |  |  |         # read the stream's info | 
            
                                                                        
                            
            
                                    
            
            
                | 97 |  |  |         sown.insert_array(DatapointArray().loadExport(directory)) | 
            
                                                                        
                            
            
                                    
            
            
                | 98 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 99 |  |  |         # Now we MIGHT be able to recover the downlink data, | 
            
                                                                        
                            
            
                                    
            
            
                | 100 |  |  |         # only if we are not logged in as the device that the stream is being inserted into | 
            
                                                                        
                            
            
                                    
            
            
                | 101 |  |  |         # So we check. When downlink is true, data is inserted into the | 
            
                                                                        
                            
            
                                    
            
            
                | 102 |  |  |         # downlink stream | 
            
                                                                        
                            
            
                                    
            
            
                | 103 |  |  |         if (sdata["downlink"] and self.db.path != self.path): | 
            
                                                                        
                            
            
                                    
            
            
                | 104 |  |  |             s.downlink = True | 
            
                                                                        
                            
            
                                    
            
            
                | 105 |  |  |             with open(os.path.join(directory, "downlink.json"), "r") as f: | 
            
                                                                        
                            
            
                                    
            
            
                | 106 |  |  |                 s.insert_array(json.load(f)) | 
            
                                                                        
                            
            
                                    
            
            
                | 107 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 108 |  |  |         # And finally, update the device | 
            
                                                                        
                            
            
                                    
            
            
                | 109 |  |  |         del sdata["name"] | 
            
                                                                        
                            
            
                                    
            
            
                | 110 |  |  |         s.set(sdata) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |     # ----------------------------------------------------------------------- | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |     # Following are getters and setters of the device's properties | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  |     def apikey(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |         """gets the device's api key. Returns None if apikey not accessible.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 |  |  |         if "apikey" in self.data: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |             return self.data["apikey"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  |         return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 |  |  |     def reset_apikey(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |         """invalidates the device's current api key, and generates a new one""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 |  |  |         self.set({"apikey": ""}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 |  |  |         return self.metadata["apikey"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 |  |  |     def public(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  |         """gets whether the device is public | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |         (this means different things based on connectordb permissions setup - connectordb.com | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 |  |  |         has this be whether the device is publically visible. Devices are individually public/private.) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |         if "public" in self.data: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  |             return self.data["public"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 |  |  |         return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 |  |  |     @public.setter | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 |  |  |     def public(self, new_public): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  |         """Attempts to set whether the device is public""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |         self.set({"public": new_public}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 |  |  |     def role(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |         """Gets the role of the device. This is the permissions level that the device has. It might | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 |  |  |         not be accessible depending on the permissions setup of ConnectorDB. Returns None if not accessible""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 |  |  |         if "role" in self.data: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 |  |  |             return self.data["role"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  |         return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 150 |  |  |     @role.setter | 
            
                                                                                                            
                            
            
                                    
            
            
                | 151 |  |  |     def role(self, new_role): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 152 |  |  |         """ Attempts to set the device's role""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 153 |  |  |         self.set({"role": new_role}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 154 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 155 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 156 |  |  |     def enabled(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 157 |  |  |         """ gets whether the device is enabled. This allows a device to notify ConnectorDB when | 
            
                                                                                                            
                            
            
                                    
            
            
                | 158 |  |  |         it is active and when it is not running""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 159 |  |  |         if "enabled" in self.data: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 160 |  |  |             return self.data["enabled"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 161 |  |  |         return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 162 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 163 |  |  |     @enabled.setter | 
            
                                                                                                            
                            
            
                                    
            
            
                | 164 |  |  |     def enabled(self, new_enabled): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 165 |  |  |         """Sets the enabled state of the device""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 166 |  |  |         self.set({"enabled": new_enabled}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 167 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 168 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 169 |  |  |     def user(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 170 |  |  |         """user returns the user which owns the given device""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 171 |  |  |         return User(self.db, self.path.split("/")[0]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 172 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 173 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 174 |  |  | # The import has to go on the bottom because py3 imports are annoying | 
            
                                                                                                            
                            
            
                                    
            
            
                | 175 |  |  | # about circular dependencies | 
            
                                                                                                            
                            
            
                                    
            
            
                | 176 |  |  | from ._user import User | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 177 |  |  | from ._stream import Stream | 
            
                                                        
            
                                    
            
            
                | 178 |  |  |  |