|
| 1 | +''' |
| 2 | +Created on Jan 4, 2014 |
| 3 | +
|
| 4 | +Licence: GNU AGPL |
| 5 | +
|
| 6 | +@author: Christian Holl |
| 7 | +''' |
| 8 | + |
| 9 | +import os |
| 10 | +import http.client |
| 11 | +import datetime |
| 12 | + |
| 13 | +class file_list_entry(object): |
| 14 | + file_name='' |
| 15 | + directory_name='' |
| 16 | + byte_size=-1 |
| 17 | + attribute_Archive=False; |
| 18 | + attribute_Directly=False; |
| 19 | + attribute_Volume=False; |
| 20 | + attribute_System=False; |
| 21 | + attribute_Hidden=False; |
| 22 | + attribute_ReadOnly=False; |
| 23 | + date_human=() |
| 24 | + time_human=() |
| 25 | + time=0 |
| 26 | + date=0 |
| 27 | + def __init__(self, file_name, directory_name, size, attributes, date, time): |
| 28 | + self.file_name=file_name |
| 29 | + self.directory_name=directory_name |
| 30 | + self.byte_size=size |
| 31 | + |
| 32 | + |
| 33 | + |
| 34 | + attributes=int(attributes) |
| 35 | + self.attribute_Archive= not not(attributes & 1<<5) |
| 36 | + self.attribute_Directly= not not(attributes & 1<<4) |
| 37 | + self.attribute_Volume= not not(attributes & 1<<3) |
| 38 | + self.attribute_System= not not(attributes & 1<<2) |
| 39 | + self.attribute_Hidden= not not(attributes & 1<<1) |
| 40 | + self.attribute_ReadOnly= not not(attributes & 1<<0) |
| 41 | + |
| 42 | + time=int(time) |
| 43 | + self.time=time; |
| 44 | + self.time_human=(((time&(0x1F<<11))>>11),((time&(0x3F<<5))>>5),(time&(0x1F))*2) |
| 45 | + |
| 46 | + date=int(date) |
| 47 | + self.date=date; |
| 48 | + self.date_human=(((date&(0x3F<<9))>>9)+1980,((date&(0x1F<<5))>>5),date&(0x1F)) |
| 49 | + |
| 50 | + |
| 51 | +class command(object): |
| 52 | + '''OPCODE - DIR DATE ADDR LENGTH DATA REQUIRED FWVERSION (Bigger/Smaller)''' |
| 53 | + Get_file_list= (100,1,0,0,0,0,'1.00.03',True) |
| 54 | + Get_the_number_of_files= (101,1,0,0,0,0,'1.00.00',True) |
| 55 | + Get_update_status= (102,0,0,0,0,0,'1.00.00',True) |
| 56 | + Get_SSID= (104,0,0,0,0,0,'1.00.00',True) |
| 57 | + Get_network_password= (105,0,0,0,0,0,'1.00.00',True) |
| 58 | + Get_MAC_address= (106,0,0,0,0,0,'1.00.00',True) |
| 59 | + Set_browser_language= (107,0,0,0,0,0,'1.00.00',True) |
| 60 | + Get_the_firmware_version= (108,0,0,0,0,0,'' ,True) |
| 61 | + Get_the_control_image= (109,0,0,0,0,0,'2.00.00',True) |
| 62 | + Get_Wireless_LAN_mode= (110,0,0,0,0,0,'2.00.00',True) |
| 63 | + Set_Wireless_LAN_timeout_length= (111,0,0,0,0,0,'2.00.00',True) |
| 64 | + Get_application_unique_information= (117,0,0,0,0,0,'2.00.00',True) |
| 65 | + Get_CID= (120,0,0,0,0,0,'1.00.03',True) |
| 66 | + Get_data_from_shared_memory= (130,0,0,1,1,0,'2.00.00',True) |
| 67 | + Set_data_to_shared_memory= (131,0,0,0,0,0,'2.00.00',True) |
| 68 | + Get_the_number_of_empty_sectors= (140,0,0,0,0,0,'1.00.03',True) |
| 69 | + Enable_Photo_Share_mode= (200,0,0,0,0,0,'2.00.00',True) |
| 70 | + Disable_Photo_Share_mode= (201,0,0,0,0,0,'2.00.00',True) |
| 71 | + Get_Photo_Share_mode_status= (202,0,0,0,0,0,'2.00.00',True) |
| 72 | + Get_SSID_for_Photo_Share_mode= (203,0,0,0,0,0,'2.00.00',True) |
| 73 | + |
| 74 | +class connection(object): |
| 75 | + ''' |
| 76 | + classdocs |
| 77 | + ''' |
| 78 | + |
| 79 | + list_directory=100 |
| 80 | + fwversion='' |
| 81 | + host=0 |
| 82 | + port=0 |
| 83 | + timeout=0 |
| 84 | + def __init__(self, host, port, timeout): |
| 85 | + ''' |
| 86 | + Constructor |
| 87 | + ''' |
| 88 | + self.host=host |
| 89 | + self.port=port |
| 90 | + self.timeout=timeout |
| 91 | + |
| 92 | + |
| 93 | + def send_command(self, opcode, directory='', date=-1, addr=-1, data=(), length=-1): |
| 94 | + if(len(opcode)==8): |
| 95 | + url="/command.cgi?op=" + str(opcode[0]) |
| 96 | + |
| 97 | + if(opcode[1] and len(directory)==0 ): |
| 98 | + print("ERROR Oppcode " + str(opcode[0]) + " requires directory") |
| 99 | + return(-1,'') |
| 100 | + elif(opcode[1]): |
| 101 | + url += '&DIR=' + directory |
| 102 | + |
| 103 | + if(opcode[2] and date<0 ): |
| 104 | + print("ERROR Oppcode " + str(opcode[0]) + " requires date") |
| 105 | + return(-1,'') |
| 106 | + elif(opcode[2]): |
| 107 | + url += '&DATE=' + date |
| 108 | + |
| 109 | + if(opcode[3] and addr<0 ): |
| 110 | + print("ERROR Oppcode " + str(opcode[0]) + " requires addr") |
| 111 | + return(-1,'') |
| 112 | + elif(opcode[3]): |
| 113 | + url += '&ADDR=' + str(addr) |
| 114 | + |
| 115 | + if(opcode[4] and length==0 ): |
| 116 | + print("ERROR Oppcode " + str(opcode[0]) + " requires length") |
| 117 | + return(-1,'') |
| 118 | + elif(opcode[4]): |
| 119 | + url += '&LEN=' + str(length) |
| 120 | + |
| 121 | + if(opcode[5] and len(data)==0 ): |
| 122 | + print("ERROR Oppcode " + str(opcode[0]) + " requires data") |
| 123 | + return(-1,'') |
| 124 | + elif(opcode[5]): |
| 125 | + url += '&DATA=' + data |
| 126 | + |
| 127 | + #Is it a firmware query? |
| 128 | + if(len(opcode[6])!=0): |
| 129 | + |
| 130 | + if(len(self.fwversion)==0): |
| 131 | + |
| 132 | + (ret, ver)=self.send_command(command.Get_the_firmware_version) |
| 133 | + if(not ret): |
| 134 | + self.fwversion=ver.decode("utf-8")[9:] |
| 135 | + print("Firmware is: ") |
| 136 | + print(self.fwversion) |
| 137 | + else: |
| 138 | + if(ret!=-2): |
| 139 | + print("ERROR: Could not determine firmware version!") |
| 140 | + return(-1,'') |
| 141 | + |
| 142 | + if(opcode[7]): #must be bigger than or equal to firmware version |
| 143 | + if(opcode[6]<self.fwversion): |
| 144 | + print("ERROR Opcode " + str(opcode[0]) + " not supported in firmware!") |
| 145 | + return(-1,'') |
| 146 | + else: |
| 147 | + if(opcode[6]>self.fwversion): |
| 148 | + print("ERROR Opcode " + str(opcode[0]) + " not supported in firmware!") |
| 149 | + return(-1,'') |
| 150 | + |
| 151 | + |
| 152 | + #Connect |
| 153 | + connection = http.client.HTTPConnection(self.host, self.port, timeout=self.timeout) |
| 154 | + |
| 155 | + try: |
| 156 | + connection.request("GET", url) |
| 157 | + response=connection.getresponse(); |
| 158 | + return (response.status!=200,response.read()) |
| 159 | + except: |
| 160 | + return (-2,'') |
| 161 | + pass |
| 162 | + |
| 163 | + |
| 164 | + def get_file_list(self,directory): |
| 165 | + (ret,lst)=self.send_command(command.Get_file_list,directory=directory) |
| 166 | + |
| 167 | + if(ret==0): |
| 168 | + |
| 169 | + lines=lst.decode("utf-8").split("\r\n") |
| 170 | + if(lines[0]=="WLANSD_FILELIST"): |
| 171 | + lines=lines[1:-1] #skip headline, and current dir at the end |
| 172 | + else: |
| 173 | + return (0,()) |
| 174 | + |
| 175 | + outlst=[] |
| 176 | + for file in lines: |
| 177 | + e=file.split(",") |
| 178 | + |
| 179 | + if(len(e)!=6): |
| 180 | + print("Error file list entry has " +str(len(e)) +" entrie(s) instead of expected 6, skipping entry") |
| 181 | + continue; |
| 182 | + #(file_name, directory_name, size, attributes, date, time): |
| 183 | + f=file_list_entry(e[1],e[0],int(e[2]),int(e[3]),int(e[4]),int(e[5])) |
| 184 | + outlst.append(f) |
| 185 | + |
| 186 | + return (0,outlst) |
| 187 | + else: |
| 188 | + return (1,()) |
| 189 | + |
| 190 | + def download_file(self, remote_location, local_path='', local_file_name=''): |
| 191 | + conn = http.client.HTTPConnection(self.host) |
| 192 | + if(len(local_file_name)==0): |
| 193 | + local_file_name = remote_location.split('/')[-1] |
| 194 | + file_size=0 |
| 195 | + |
| 196 | + |
| 197 | + #does folder exist? |
| 198 | + if(not os.access(local_path, os.R_OK)): |
| 199 | + return (2,0,'') |
| 200 | + |
| 201 | + #add / if it is not there already |
| 202 | + if(len(local_path)!=0 and local_path[-1]!='/'): |
| 203 | + local_path+='/' |
| 204 | + |
| 205 | + #combine path and file |
| 206 | + local_path+=local_file_name |
| 207 | + |
| 208 | + #does file exist already? |
| 209 | + if(os.path.isfile(local_path)): |
| 210 | + return (3,0,'') |
| 211 | + |
| 212 | + print("Downloading:" + local_file_name) |
| 213 | + #get the stuff from the FlashAir |
| 214 | + conn.request("GET", remote_location) |
| 215 | + download = conn.getresponse() |
| 216 | + file = open(local_path, 'wb') |
| 217 | + if(download.status==200): |
| 218 | + |
| 219 | + while True: |
| 220 | + buffer=download.read(1024*8) |
| 221 | + if not buffer: |
| 222 | + break; |
| 223 | + file_size += len(buffer) |
| 224 | + file.write(buffer) |
| 225 | + file.close() |
| 226 | + return (int(download.status!=200), file_size,local_path) |
| 227 | + |
| 228 | + def download_file_list_entry(self, entry,local_path='', local_filename=''): |
| 229 | + (status,size,local_filename)=self.download_file(entry.directory_name + '/' + entry.file_name, local_path, local_filename) |
| 230 | + if(status): |
| 231 | + return(1) |
| 232 | + |
| 233 | + |
| 234 | + if(size!=entry.byte_size): |
| 235 | + os.remove(local_filename) |
| 236 | + return(2) |
| 237 | + |
| 238 | + return(0) |
| 239 | + |
| 240 | + def sync_folder_to_remote_folder(self,remote_path='',local_path='',extensions=['JPG']): |
| 241 | + #all extensions to upper case |
| 242 | + extensions=[x.upper() for x in extensions] |
| 243 | + |
| 244 | + #get list of remote files |
| 245 | + (status, outlist)=self.get_file_list(remote_path) |
| 246 | + if(not status and len(outlist)): |
| 247 | + if(not os.access(local_path, os.R_OK)): |
| 248 | + return 2 |
| 249 | + for entry in outlist: |
| 250 | + if ((entry.file_name.split('.')[-1].upper() in extensions) or len(extensions)==0): |
| 251 | + self.download_file_list_entry(entry, local_path) |
| 252 | + |
| 253 | + |
| 254 | + |
0 commit comments