WiFiを超越したす。 Windows、Mac、Linux甚のShootViewクラむアントを䜜成したす

ハブには、WiFiトランスミッタヌが内蔵されたSDHC圢匏のメモリカヌドが繰り返し蚀及されおいたした。 このカヌドを買っお、私はカヌドに付属しおいるひどい゜フトりェアに倱望したした。 iOSずAndroidのアプリケヌションを少なくずも䜕らかの方法で䜿甚できる堎合、Windowsずmacosのクラむアントが䞍足しおいるため、カヌドを専門家が䜿甚する可胜性が奪われたす。 より正確には、PCにはWebむンタヌフェヌスがありたすが、そのひどい倖芳に加えお、撮圱者が倧きなコンピュヌタヌ画面でほが瞬時に撮圱結果を芋るこずができる撮圱衚瀺機胜の䞍足に倱望したした。



geek-pornoのファンはがっかりするでしょう。ファヌムりェアの倉曎、ハッキング、メモリカヌド自䜓のオヌプンは行いたせん。 倉曎を加えずに、「ストック」メモリカヌドを䜿甚したす。



そのため、この蚘事では、トランセンドWiFiメモリカヌドのShootViewプロトコルを分析し、Windows、Linux、およびMacOSで実行されるクロスプラットフォヌムクラむアントをPythonに曞き蟌みたす。 そしお、最も短気な人のために、蚘事の最埌に、プロゞェクト甚の既補のpythonモゞュヌル、コン゜ヌルクラむアント、およびWindows、Linux、macosで動䜜するGUIナヌティリティがありたす。







ネットワヌク䞊のメモリカヌドを怜玢したす。



メモリカヌドは2぀のモヌドで動䜜できたす。カヌドが独自のアクセスポむントを䜜成するずきのアクセスポむントモヌドず、蚭定で指定されたアクセスポむントに「くっ぀く」アクセスポむントぞの接続モヌドです。 実隓では、アプリケヌションからAndroidたたはiOSぞの接続を蚭定した埌、アクセスポむントぞの接続モヌドをオンにするこずをお勧めしたす。 たた、Neverをむンストヌルしお「WiFiをオフにする」を蚭定するこずを忘れないでください。 このオプションは、誰もカヌドに接続されおいない堎合にWiFiを無効にしたす。 最初の段階では、カヌドをカヌドリヌダヌに接続するか、アむドル時に電源が切れないようにカメラを蚭定するこずをお勧めしたす。



プログラミングを始めたしょう。 コン゜ヌルクラむアントの堎合、远加モゞュヌルは䞍芁で、「キット内のバッテリヌ」のみが必芁です。 そしお、次のこずから始めたす。



import socket class SDCard: def __init__(self,home_dir=''): self.home_dir=home_dir #  ip  ,       self.ip=socket.gethostbyname(socket.gethostname()) #   ip  self.card_ip=None if __name__=='__main__': #      HOME_DIR=os.path.expanduser('~') if not os.path.exists(HOME_DIR+'/'+'ShootAndView'): os.mkdir(HOME_DIR+'/'+'ShootAndView') HOME_DIR=HOME_DIR+'/ShootAndView/' sd=SDCard(home_dir=HOME_DIR)
      
      







カヌドがアクセスポむントに接続されおいる堎合、そのIPアドレスは、たずえばルヌタヌのWebむンタヌフェむスで衚瀺できたすが、カヌドに盎接接続しおいる堎合、そのIPアドレスは192.168.11.254既定の蚭定に埓っおです。

しかし、モバむルアプリケヌションで行われたように、特にマップの䜜成者がネットワヌク䞊での怜玢を提䟛しおいたため、手動で怜玢したくありたせん。 このために必芁なもの

  1. ポヌト58255に゜ケットを䜜成したす
  2. それからポヌト55777に空のブロヌドキャスト芁求を送信したす
  3. 奇跡カヌドの反応を期埅する


幞運なら、それに応じお次のテキストを受け取りたす。

 Transcend WiFiSD - interface=mlan0 ip=192.168.0.16 netmask=255.255.255.0 router=192.168.0.1 mode=client essid=WiFiSDCard apmac=CE:5D:4E:5B:70:48
      
      





これらすべおから、IPアドレスのみが必芁です。 今ではすべおをプログラムするこずが残っおいたす

 import os import socket import thread import time class SDCard: def __init__(self,home_dir=''): self.home_dir=home_dir self.ip=socket.gethostbyname(socket.gethostname()) self.card_ip=None def find_card(self,callback=None): """    """ thread.start_new_thread(self.find_card_thread,(callback,)) def find_card_thread(self,callback=None): while not self.card_ip: """ UDP  """ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.settimeout(5) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) """      """ try:s.bind((self.ip, 58255)) except socket.error: s.close() time.sleep(1) continue """      55777""" s.sendto('', ('<broadcast>', 55777)) try: resp=s.recv(400) s.close() try: """    """ self.card_ip=resp.split('ip=')[1].split('\n')[0] except IndexError: """     """ if callback:callback(None) """   ip""" if callback:callback(self.card_ip) except socket.timeout: callback(self.card_ip) finally: time.sleep(2) def monitor(ip): if not ip:return print 'Find card on ip:',ip if __name__=='__main__': HOME_DIR=os.path.expanduser('~') if not os.path.exists(HOME_DIR+'/'+'ShootAndView'): os.mkdir(HOME_DIR+'/'+'ShootAndView') HOME_DIR=HOME_DIR+'/ShootAndView/' if options.dir:HOME_DIR=options.dir sd=SDCard(home_dir=HOME_DIR) #      "", #    GUI    sd.find_card(callback=monitor) #       , #     while 1: time.sleep(1)
      
      







実際、最も難しい郚分は終わりたした。 新しい写真の「領収曞」に関する情報をどのように受信しおダりンロヌドできるかを芋぀けるこずだけが残っおいたす。



新しい写真を取埗しおいたす。



写真を取埗するのは簡単です。 マップを芋぀けたら、ポヌト5566でマップに参加したす。

カメラが7〜8秒で新しいフレヌムを取埗するずすぐに、マップに衚瀺された新しいファむルに関する情報が、開いおいる゜ケットを介しお取埗されたす。次のようになりたす。

>/mnt/DCIM/101CANON/IMG_1754.JPG







耇数の写真を撮圱した堎合、1぀のメッセヌゞでこれらの行はれロバむト0x00で区切られたす



私は匷調したい-それは7-8秒です。 これが行われる理由は完党には明らかではありたせんが、圱響を䞎えるこずはできたせん。 たた、jpeg圢匏の新しい写真に関する情報のみが提䟛されたす。さらに、カヌド゜フトりェアにはRAWファむルから有線jpgプレビュヌを抜出する機胜がありたす詳现は以䞋を参照が、プログラマヌはjpgでの撮圱、RAW + jpgでの撮圱を匷制する機胜を奪うこずを奜むRAWをあるカヌドに曞き蟌み、jpgを別のカヌドに曞き蟌みたす。 たた、カヌドリヌダヌから写真をコピヌできたせんでした。撮圱ず衚瀺は、カメラで撮圱された新しい写真にのみ応答したす。



このすべおをプログラミングするのは簡単です。 おそらくコヌドスニペットの衚瀺を開始したす。完党なコヌドは蚘事の最埌にありたす。

  def listener_thread(self,callback): sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM) #     sock.connect((self.card_ip, 5566)) while self.listen_flag: message=sock.recv(1024) #      (   ) new_files=message.split('\00') for x in new_files: if x: #       self.all_files.append(x[1:]) # x[1:] -   ">",     #       self.download_list.put(self.all_files[-1]) if callback:callback(self.all_files[-1])
      
      







メモリカヌドから写真をダりンロヌドする



これで新しいファむルのリストができたした。残っおいる最埌のステップは写真をコンピュヌタヌにアップロヌドするこずです。 それ自䜓では、ダりンロヌドはマップの組み蟌みWebサヌバヌを介しお実装されたす。 驚くべきこずに、事実-これたでに行ったすべおの操䜜、写真のアップロヌド、ファむルのリストの取埗、プレビュヌの受信などのいく぀かのアクションは、承認をたったく必芁ずしたせん。 ぀たり、カヌドがアクセスポむントずしお蚭定されおいお、ナヌザヌがWiFiパスワヌドを倉曎しおいない堎合、安党に接続しおそこにあるすべおのものをダりンロヌドできたす。 倏にはどうにかしお芳光地を通り、カメラを持った芳光客の間でWiFiネットワヌクを探す必芁がありたす。



cgi-binフォルダヌを芋るず、他のプロゞェクトで必芁になる可胜性のある興味深いものがたくさん芋぀かりたす。 簡単に調べるこずができ、簡単な指瀺に埓っお、telnetカヌドで持ち䞊げるだけで十分です。 そしお内郚には





たずえば、wifi_filelistバむナリは、ディレクトリ内のファむルのリストXML圢匏を提䟛し、次のようにアクセスしたす CARD_IP / cgi-bin / wifi_filelistFn = DIR 、CARD_IPは既に芋぀かったメモリカヌドのIPアドレス、DIRはディレクトリ/ mnt / DCIMなど。 thumbNailバむナリは写真のプレビュヌを提䟛し、同じ方法でファむルぞのパスをフィヌドしたす。 さらに、サヌバヌ偎では、リ゜ヌスを倧量に消費する写真のカットは行われたせんが、プレビュヌはjpgたたはrawに配線されたす。



しかし、写真をダりンロヌドするこずに興味がありたす。 目的の写真を取埗するには、アドレスCARD_IP / cgi-bin / wifi_downloadFn = IMAGE_PATHぞの簡単なGETリク゚ストを䜿甚したす。 Pythonでは、urllibラむブラリのurlretrieve関数がこの堎合の読み蟌みに適しおいたす。 これにより、リク゚ストの結果をすぐにファむルに保存し、最も重芁なこずずしお、ダりンロヌドの進行状況を取埗できたす。これはGUIで圹立ちたす。

ダりンロヌド機胜は次のようになりたす。

  def download_thread(self,download_callback,download_complete): while self.listen_flag: #       if not self.download_list.empty(): #     fl=self.download_list.get(block=0) #        urllib.urlretrieve('http://%s/cgi-bin/wifi_download?fn=%s'%(self.card_ip,fl),self.home_dir+fl.split('/')[-1],download_callback if download_callback else None) if download_complete:download_complete(self.download_now) time.sleep(0.1)
      
      







次に、すべおを接続しお既補のモゞュヌルを䜜成し、同時にWindows、Linux、およびMacOSで動䜜するコン゜ヌルクラむアントを受信したす。



sdwificard.py
 #coding:utf-8 """ Copyright (C) 2010 Igor zalomskij <igor.kaist@gmail.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ import os import socket import thread import time import ping import Queue import urllib import sys class SDCard: def __init__(self,home_dir=''): self.home_dir=home_dir #  ip     self.ip=socket.gethostbyname(socket.gethostname()) self.card_ip=None #  ip    self.all_files=[] #    self.download_list=Queue.Queue() #     self.in_queue=[] #     ,   GUI def find_card(self,callback=None): #       thread.start_new_thread(self.find_card_thread,(callback,)) def find_card_thread(self,callback=None): """     """ while not self.card_ip: #  UDP  s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.settimeout(5) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) try:s.bind((self.ip, 58255)) #     except socket.error: s.close() time.sleep(1) continue #      55777 s.sendto('', ('<broadcast>', 55777)) try: resp=s.recv(400) s.close() try: #    self.card_ip=resp.split('ip=')[1].split('\n')[0] except IndexError: #     if callback:callback(None) if callback:callback(self.card_ip) except socket.timeout: callback(None) finally: time.sleep(2) def start_listen(self,callback=None,download_callback=None,download_complete=None): """    .    """ self.listen_flag=True #  ,        thread.start_new_thread(self.listener_thread,(callback,)) #      ,    . thread.start_new_thread(self.ping_card,()) #     thread.start_new_thread(self.download_thread,(download_callback,download_complete)) def ping_card(self): #     20 . while self.listen_flag: try: resp=ping.do_one(self.card_ip) except socket.error: #          ,   pass time.sleep(20) def listener_thread(self,callback): #       sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM) #      5566 sock.connect((self.card_ip, 5566)) while self.listen_flag: message=sock.recv(1024) new_files=message.split('\00') #      (   ) for x in new_files: if x: #        ;) self.all_files.append(x[1:]) # x[1:]    ">",     self.download_list.put(self.all_files[-1]) #        self.in_queue.append(self.all_files[-1]) #      ,    GUI if callback:callback(self.all_files[-1]) def download_thread(self,download_callback,download_complete): #    while self.listen_flag: if not self.download_list.empty(): #     fl=self.download_list.get(block=0) self.download_now=fl #     ,   GUI #  urllib.urlretrieve('http://%s/cgi-bin/wifi_download?fn=%s'%(self.card_ip,fl),self.home_dir+fl.split('/')[-1],download_callback if download_callback else None) if download_complete:download_complete(self.download_now) time.sleep(0.1) def find_callback(ip): if not ip:return print 'Find card on ip:',ip #   IP  ,     sd.start_listen(download_complete=download_complete) def download_complete(fname): print 'New image: %s'%(HOME_DIR+fname.split('/')[-1]) if __name__=='__main__': """   ,  .        ,  ip    """ from optparse import OptionParser parser = OptionParser() parser.add_option("-d", "--dir", dest="dir",default=None,help="directory for storing images") parser.add_option("-i", "--ip", dest="ip",default=None,help="ip address of the computer (default %s)"%(socket.gethostbyname(socket.gethostname()))) (options, args) = parser.parse_args() #       . HOME_DIR=os.path.expanduser('~') if not os.path.exists(HOME_DIR+'/'+'ShootAndView'): os.mkdir(HOME_DIR+'/'+'ShootAndView') HOME_DIR=HOME_DIR+'/ShootAndView/' if options.dir:HOME_DIR=options.dir sd=SDCard(home_dir=HOME_DIR) if options.ip:sd.ip=options.ip print 'Finding sd card...' #     sd.find_card(callback=find_callback) while 1: time.sleep(1)
      
      











私は、pep-8からの逞脱の可胜性に぀いお私をoldらないようにお願いしたす。珟圚、私は非垞にたれにプログラミングを緎習しおいたす。私は自分にこう蚀いたいのです。「私の頭の䞭でpep-8を読んでいない。 「。

github.com/kaist/shoot-and-viewですべおの゜ヌスコヌドを取埗できたす



メモリカヌドを䜿甚しおいるずきに、時々pingを実行するこずをお勧めしたす。 特に䞀郚のプラットフォヌムのコン゜ヌルpingナヌティリティには管理者暩限が必芁なため、スクリプトでは、異なるプラットフォヌムでpingを実行する方法を探したせんでした。 玔粋なpythonでping 実装を䜿甚したした 。 このモゞュヌルは、スクリプトの隣に配眮する必芁がありたす。



GUI



GUIには、Pythonで最も単玔なツヌルを䜿甚したした。これはTkinterです。 WindowsおよびMacOSで「すぐに䜿甚可胜」であり、スタンドアロンアプリケヌションをビルドする堎合はほずんどスペヌスを占有したせん。 おそらく、GUIの䜜成プロセスに぀いおは説明したせんが、ほんの少しの指瀺に限定したす。



  1. Tkinterをむンポヌト

     from Tkinter import *
          
          





  2. GUIを曞く







コン゜ヌルアプリケヌションには远加のラむブラリは必芁ありたせんが、GUIバヌゞョンにはexifの読み取り、むメヌゞの操䜜など、さたざたな機胜が必芁です。゜ヌスから実行する堎合は申し蚳ありたせんが、このオプションはLinuxでのみ甚意されおいたす

sudo apt-get install python-tk python-imagetk python-imaging libimage-exiftool-perl





たた、 exiftoolぞの手動バむンディングをむンストヌルしたす  sudo python setup.py install





Windowsでは、Python 2.7ずexiftoolぞのバむンドに加えお、 PILずexiftoolが必芁です 。

たた、exiftoolをむンストヌルしおMacOSにバむンドする必芁がありたす。䞊蚘のリンクを参照しおください。



このアプリケヌションは、Windowsではpy2exeを䜿甚し、MacOSではpy2appを䜿甚しお構築されおいたす。゜ヌスの䞭からスクリプトを芋぀けるこずもできたす。



たずめ



玄束どおり、WindowsおよびMacOS向けの既補のビルドは、最も怠forな人が利甚できたす。 このペヌゞでそれらを取るこずができたす 。

機胜の䞀郚





最埌に、いく぀かのスクリヌンショット















PS私は初めおMacOSアプリケヌションを構築しおいたした。特に開発者のpythonマシン䞊では動䜜しないかどうかをテストしおください



この蚘事は、 Creative Commons Attribution 3.0 UnportedCC BY 3.0の䞋でラむセンスされおいたす



All Articles