ä»æ¥ã¯ãã¢ãã€ã«ããã€ã¹ããã³ã³ãã¥ãŒã¿ãŒãå¶åŸ¡ããæ¹æ³ã«ã€ããŠèª¬æããŸãã ããããããã¯radminã®å¥ã®é¡äŒŒç©ã§ã¯ãªããå人ã®ã³ã³ãã¥ãŒã¿ãŒãæš¡æ¬ããæ¹æ³ã®äŸã§ããããŸããã ããã¯ãããŒã¢ã³ã®ãªã¢ãŒãå¶åŸ¡ããŸãã¯ããããPythonã§æžãããããŒã¢ã³ã管çããããã®ã€ã³ã¿ãŒãã§ãŒã¹ã®äœæã«é¢ãããã®ã§ãã
ã¢ãŒããã¯ãã£ã¯éåžžã«åçŽã§ãã
- ããªã¢ãŒãã³ã³ãããŒã«ã¢ããªã -ã¢ãã€ã«ããã€ã¹ã®ã¯ã©ã€ã¢ã³ãããŒããå®è£ ããKivyã¢ããªã±ãŒã·ã§ã³ã
- ããªã¢ãŒãã³ã³ãããŒã«ã -REST APIããã³ããŒã¿ããŒã¹ãšã®å¯Ÿè©±ãå®è£ ããDjangoã¢ããªã±ãŒã·ã§ã³ã
- IRemoteControl-åä¿¡ããã³ãã³ããåŠçããããžãã¯ãå®è£ ããã¯ã©ã¹ïŒããŒã¢ã³ã§äœ¿çšãããŸãïŒã
èå³ãããã°ãç«ã«ããããã
å®è£ ãé²ããåã«ããããžã§ã¯ãã«ã¿ãã°ããæºåãããããšãææ¡ããŸãã å¿ èŠæ§ïŒ
- å¥ã®Pythonä»®æ³ç°å¢ãäœæãã
virtualenv .env
- æ°ããDjangoãããžã§ã¯ãïŒäŸïŒwebïŒãäœæããŸã
django-admin startproject web
- Androidã¢ããªã±ãŒã·ã§ã³çšã®ãã£ã¬ã¯ããªïŒui_appãªã©ïŒãäœæããŸãã ã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã«é¢ãããã¹ãŠã®æäœã¯ããã®ãã£ã¬ã¯ããªã«å¯ŸããŠå®è¡ãããŸãã
ããªã¢ã³ã³ã
ãµãŒããŒåŽããå§ããŸããã-Djangoã¢ããªã±ãŒã·ã§ã³ã æ°ããã¢ããªã±ãŒã·ã§ã³ãäœæããã¹ãŒããŒãŠãŒã¶ãŒãè¿œå ããŸãã
python manage.py startapp remotecontrol
Djangoãããžã§ã¯ãã§äœ¿çšããã¢ããªã±ãŒã·ã§ã³ã«ããã«è¿œå ããããšããå§ãããŸãïŒweb \ settings.pyãŸãã¯ãwebãã®ä»£ããã«-Djnagoãããžã§ã¯ãã®ååïŒïŒ
INSTALLED_APPS = [ ....... 'remotecontrol', ]
DBãšã¹ãŒããŒãŠãŒã¶ãŒãäœæããŸãã
python manage.py migrate python manage.py createsuperuser
èšå®ãå®äºããããã¢ããªã±ãŒã·ã§ã³ã«é²ã¿ãŸãã
ã¢ãã«ïŒremotecontrol \ models.pyïŒ
ã¢ãŒããã¯ãã£ã«ã¯1ã€ã®ã¢ãã«ãããªã-ããã¯ãããŒã¢ã³ãå¿çããå¿ èŠãããããŒã ã§ãã ã¢ãã«ãã£ãŒã«ãïŒ
- ã³ãã³ãã³ãŒã -4ã€ã®ã³ãã³ãã䜿çšããŸãïŒãäžæåæ¢ãããåéãããåèµ·åãããã³ã³ãããŒã«ããã«ãç¡å¹ã«ããã
- ããŒã ã®ã¹ããŒã¿ã¹ -ãäœææžã¿ãããåŠçäžãããå®äºãããæåŠãã®4ã€ã®ç¶æ ãå¯èœã§ãã
- IP
- ãªããžã§ã¯ãäœææ¥
ããŒã ãšã¹ããŒã¿ã¹ã®è©³çŽ°ã«ã€ããŠã¯ã以äžãåç §ããŠãã ãã ã
ã¢ãã«ã«ã€ããŠèª¬æããŸãã
# -*- coding: utf-8 -*- from django.db import models # CODE_PAUSE = 1 # "" CODE_RESUME = 2 # "" CODE_RESTART = 3 # "" CODE_REMOTE_OFF = 4 # " " COMMANDS = ( (CODE_RESTART, 'Restart'), (CODE_PAUSE, 'Pause'), (CODE_RESUME, 'Resume'), (CODE_REMOTE_OFF, 'Disable remote control'), ) class Command(models.Model): # STATUS_CREATE = 1 # "" STATUS_PROCESS = 2 # " " STATUS_DONE = 3 # "" STATUS_DECLINE = 4 # "" STATUS_CHOICES = ( (STATUS_CREATE, 'Created'), (STATUS_PROCESS, 'In progress...'), (STATUS_DONE, 'DONE'), (STATUS_DECLINE, 'Declined'), ) # created = models.DateTimeField(auto_now_add=True) ip = models.GenericIPAddressField() code = models.IntegerField(choices=COMMANDS) status = models.IntegerField(choices=STATUS_CHOICES, default=STATUS_CREATE)
å°ããªãã¢ããã°ã¬ãŒããã¢ãã«ïŒ
1.æšæºãããŒãžã£ãŒãå±éããŸãã ãäœææžã¿ãç¶æ ããã³ãåŠçäžãç¶æ ã®ã³ãã³ããåä¿¡ããã¡ãœãããè¿œå ããŸãã
ãããŒãžã£ãŒã«ã€ããŠèª¬æããŸãããã
class CommandManager(models.Manager): # "", def created(self): return super(CommandManager, self).get_queryset().filter( status=Command.STATUS_CREATE).order_by('created') # " ", def processing(self): return super(CommandManager, self).get_queryset().filter( status=Command.STATUS_PROCESS).order_by('created')
ãããŠãã¢ãã«ã«è¿œå ããŸãïŒ
class Command(models.Model): ....... objects = CommandManager()
2.ç¶æ ãã§ãã¯ã®æ¹æ³ãšã³ãã³ãã®ç¶æ ãèšå®ããæ¹æ³ãè¿œå ããŸãã
è¿œå ããŸãã ã¡ãœããïŒ
class Command(models.Model): ....... # def is_created(self): return self.status == self.STATUS_CREATE def is_processing(self): return self.status == self.STATUS_PROCESS def is_done(self): return self.status == self.STATUS_DONE def is_declined(self): return self.status == self.STATUS_DECLINE # def __update_command(self, status): self.status = status self.save() def set_process(self): self.__update_command(Command.STATUS_PROCESS) def set_done(self): self.__update_command(Command.STATUS_DONE) def set_decline(self): self.__update_command(Command.STATUS_DECLINE)
泚ïŒãã¡ããããããã®ã¡ãœãããªãã§ãå®è¡ã§ããŸãã ãã®å ŽåãDjango ORMã§åäœããã³ãŒãã§ã¯ãå®æ°ã䜿çšããã³ãã³ãæŽæ°ã®ããžãã¯ïŒå°ãªããšã2è¡ã§ãããããã§ãïŒãèšè¿°ããå¿ èŠããããŸãããããã¯ããŸã䟿å©ã§ã¯ãããŸããã å¿ èŠãªã¡ãœããããã«ããæ¹ãã¯ããã«äŸ¿å©ã§ãã ãããããã®ã¢ãããŒããæŠå¿µãšççŸããå Žåã¯ãã³ã¡ã³ãã®è°è«ãåãã§èããŸãã
models.pyã®å®å
šãªãªã¹ãïŒ
# -*- coding: utf-8 -*- from django.db import models # CODE_PAUSE = 1 # "" CODE_RESUME = 2 # "" CODE_RESTART = 3 # "" CODE_REMOTE_OFF = 4 # " " COMMANDS = ( (CODE_RESTART, 'Restart'), (CODE_PAUSE, 'Pause'), (CODE_RESUME, 'Resume'), (CODE_REMOTE_OFF, 'Disable remote control'), ) class CommandManager(models.Manager): # "", def created(self): return super(CommandManager, self).get_queryset().filter( status=Command.STATUS_CREATE).order_by('created') # " ", def processing(self): return super(CommandManager, self).get_queryset().filter( status=Command.STATUS_PROCESS).order_by('created') class Command(models.Model): # STATUS_CREATE = 1 # "" STATUS_PROCESS = 2 # " " STATUS_DONE = 3 # "" STATUS_DECLINE = 4 # "" STATUS_CHOICES = ( (STATUS_CREATE, 'Created'), (STATUS_PROCESS, 'In progress...'), (STATUS_DONE, 'DONE'), (STATUS_DECLINE, 'Declined'), ) # created = models.DateTimeField(auto_now_add=True) ip = models.GenericIPAddressField() code = models.IntegerField(choices=COMMANDS) status = models.IntegerField(choices=STATUS_CHOICES, default=STATUS_CREATE) objects = CommandManager() # def is_created(self): return self.status == self.STATUS_CREATE def is_processing(self): return self.status == self.STATUS_PROCESS def is_done(self): return self.status == self.STATUS_DONE def is_declined(self): return self.status == self.STATUS_DECLINE # def set_process(self): self.__update_command(Command.STATUS_PROCESS) def set_done(self): self.__update_command(Command.STATUS_DONE) def set_decline(self): self.__update_command(Command.STATUS_DECLINE) def __update_command(self, status): self.status = status self.save() # - STATUS_COLORS = { STATUS_CREATE: '000000', STATUS_PROCESS: 'FFBB00', STATUS_DONE: '00BB00', STATUS_DECLINE: 'FF0000', } def colored_status(self): return '<span style="color: #%s;">%s</span>' % (self.STATUS_COLORS[self.status], self.get_status_display()) colored_status.allow_tags = True colored_status.short_description = 'Status' # REST API def status_dsp(self): return self.get_status_display() def code_dsp(self): return self.get_code_display()
管çããã«ïŒremotecontrol \ admin.pyïŒ
泚ïŒä»¥äžã§ã¯ãã¯ã©ã€ã¢ã³ãIPãå€å¥ããããã«django-ipwareã¢ããªã±ãŒã·ã§ã³ãå¿ èŠã«ãªããŸãã
pip install django-ipware
ããã§ã¯ãã¹ãŠããã€ãã£ãã«è¡ãããŸãã管çããã«ã«ã¢ãã«ãç»é²ããè¡šã«è¡šç€ºãããŠããåãšãã©ãŒã ã®ãã£ãŒã«ãã説æããŸãã å¯äžã®æ³šæç¹-ãªããžã§ã¯ãã«ã¯ã©ã€ã¢ã³ãIPãä¿åããã«ã¯ãsaveã¡ãœããããªãŒããŒã©ã€ãããå¿ èŠããããŸãã
admin.pyã®ãªã¹ãïŒ
# -*- coding: utf-8 -*- from django.contrib import admin from ipware.ip import get_ip from .models import Command @admin.register(Command) class CommandAdmin(admin.ModelAdmin): # list_display = ('created', 'code', 'colored_status', 'ip') # list_filter = ('code', 'status', 'ip') # \ fields = (('code', 'status'), ) # def save_model(self, request, obj, form, change): if obj.ip is None: # IP obj.ip = get_ip(request) obj.save()
ã¢ãã«ã®å€æŽãããŒã¿ããŒã¹ã«é©çšããããšãå¿ããªãã§ãã ããïŒ
python manage.py makemigrations remotecontrol python manage.py migrate remotecontrol
ãã®çµæããªããžã§ã¯ããäœæ/ç·šéããããšãã§ããŸã...

...ãããŠã管çããã«ã§ãªããžã§ã¯ãã®ãªã¹ãã衚瀺ããŸãã

ã³ãã³ãåŠçã®ããžãã¯ã®å®è£ ã«é²ã¿ãŸãã
ã¯ã©ã¹IRemoteControl
äžèšã®ãšããã4ã€ã®ããŒã ããããŸãã
- ãäžæåæ¢ã -ã¡ã€ã³ããŒã¢ã³ãµã€ã¯ã«ãäžæåæ¢ãããåéãããåèµ·åããããªã¢ãŒãã®ç¡å¹åããé€ããã¹ãŠã®ã³ãã³ããç¡èŠããŸãã
- ãåéã -æªéã®ã¡ã€ã³ãµã€ã¯ã«ãåéããŸãã
- ãåèµ·åã -ããŒã¢ã³ã®ååæåãæ§æã®åèªã¿åããªã©ãå®è¡ããŸãã ãã®ã³ãã³ãã¯ããäžæåæ¢ãã³ãã³ãã®ã¢ã¯ã·ã§ã³ã®å Žåã«ãå®è¡ãããŸãããåèµ·ååŸã«ã¡ã€ã³ãµã€ã¯ã«ãåéãããŸãã
- ãã³ã³ãããŒã«ããã«ãç¡å¹ã«ããã -çä¿¡ã³ãã³ãã®åŠçãåæ¢ããŸãïŒãã以éã®ã³ãã³ãã¯ãã¹ãŠç¡èŠãããŸãïŒã ãã®ã³ãã³ãã¯ããäžæåæ¢ãã³ãã³ãã®ã¢ã¯ã·ã§ã³ã®å Žåã«ãå®è¡ãããŸãã
äœææã«ã¯ãããŒã ã«ã¹ããŒã¿ã¹ãäœææžã¿ããå²ãåœãŠãããŸãïŒããããšããCapïŒïŒã åŠçäžãã³ãã³ãã¯ãå®è¡æžã¿ãïŒã·ã¹ãã ã®ç¶æ ãå¿ èŠãªæ¡ä»¶ããã¹ãŠæºããå ŽåïŒãŸãã¯ãæåŠæžã¿ãïŒãã以å€ã®å ŽåïŒã«ãªããŸãã ã¹ããŒã¿ã¹ãåŠçäžãã¯ããé·æã«ããããããŒã ã«é©çšãããŸã-ããŒã ã®å®è¡ã«ã¯æéããããå ŽåããããŸãã ããšãã°ããäžæåæ¢ãã³ãã³ããåãåã£ãã³ãŒãã¯ãã©ã°å€ã®ã¿ãå€æŽãããåèµ·åãã³ãã³ãã¯ããè€éãªããžãã¯ã®å®è¡ãéå§ããŸãã
ã³ãã³ããåŠçããããã®ããžãã¯ã¯æ¬¡ã®ãšããã§ãã
- 1åã®å埩ã§ã1ã€ã®ã³ãã³ããåŠçãããŸãã
- ãåŠçäžãç¶æ ã®ãæãå€ããã³ãã³ããååŸããŸãã ååšããªãå Žåããäœææžã¿ãç¶æ ã®ãæãå€ãããã®ãååŸããŸãã ããã§ãªãå Žåãå埩ã¯å®äºããŠããŸãã
- ç¡å¹ãªIPããã³ãã³ããåä¿¡ããå Žå-ã¹ããŒã¿ã¹ããæåŠãã«èšå®ããŸãã å埩ãå®äºããŸããã
- ã³ã³ãããŒã«ããã«ããªãã«ãªã£ãŠããå Žåã¯ãã³ãã³ãã¹ããŒã¿ã¹ããäžæ¿èªãã«èšå®ããŸãã å埩ãå®äºããŸããã
- ã³ãã³ããããŒã¢ã³ã®çŸåšã®ç¶æ ã«å¯ŸããŠæå¹ã§ãªãå Žåãç¶æ ããæåŠãã«èšå®ããŸãã å埩ãå®äºããŸããã
- ã¹ããŒã¿ã¹ããåŠçäžãã«èšå®ãïŒå¿ èŠãªå ŽåïŒãã³ãã³ããå®è¡ããã¹ããŒã¿ã¹ããå®äºãã«èšå®ããŸãã å埩ãå®äºããŸããã
ã¯ã©ã¹ã®ããšã³ããªãã€ã³ããã¯.check_commandsïŒïŒã¡ãœããã§ããããã¯äžèšã®ããžãã¯ãå®è£ ããŸãã ããŒã¢ã³ã®ã¡ã€ã³ã«ãŒãã§åãã¡ãœãããåŒã³åºããŸãã ãäžæåæ¢ãã³ãã³ããåä¿¡ããå Žåãã¡ãœããã«ãµã€ã¯ã«ãäœæãããŸããçµäºæ¡ä»¶ã¯ãåéãã³ãã³ããåä¿¡ããããšã§ããããã«ãããããŒã¢ã³ã®äœæ¥ã§ç®çã®äžæåæ¢å¹æãéæãããŸãã
Control.pyã¢ãžã¥ãŒã«ïŒremotecontrol \ control.pyïŒ
IRemoteControlã®å®è£ ãèšè¿°ããã¢ãžã¥ãŒã«ãã¢ããªã±ãŒã·ã§ã³ãã£ã¬ã¯ããªã«é 眮ããããšãææ¡ããŸãã ãããã£ãŠã䟿å©ã«è»¢éãããDjango-appãååŸããŸãã
control.pyã®ãªã¹ã
# -*- coding: utf-8 -*- import django django.setup() from time import sleep from remotecontrol.models import * class IRemoteControl(object): # IP. , . IP_WHITE_LIST = ['127.0.0.1'] # CODE_REMOTE_OFF REMOTE_ENABLED = True # def __get_command(self): commands = Command.objects.processing() if len(commands) == 0: commands = Command.objects.created() if len(commands) == 0: return None command = commands[0] if self.IP_WHITE_LIST and command.ip not in self.IP_WHITE_LIST: print('Wrong IP: %s' % command.ip) elif not self.REMOTE_ENABLED: print('Remote is disabled') else: return command self.__update_command(command.set_decline) # "" def __restart(self, command): if command.is_created(): self.__update_command(command.set_process) print('... Restarting ...') sleep(5) self.__update_command(command.set_done) print('... Restart complete ...') # def __update_command(self, method): try: method() except Exception as e: print('Cannot update command. Reason: %s' % e) # def check_commands(self): pause = False enter = True while enter or pause: enter = False command = self.__get_command() if command is not None: if command.code == CODE_REMOTE_OFF: self.__update_command(command.set_done) print('... !!! WARNING !!! Remote control is DISABLED ...') self.REMOTE_ENABLED = False elif command.code == CODE_RESTART: self.__restart(command) pause = False elif pause: if command.code == CODE_RESUME: self.__update_command(command.set_done) print('... Resuming ...') pause = False else: self.__update_command(command.set_decline) else: if command.code == CODE_PAUSE: self.__update_command(command.set_done) print('... Waiting for resume ...') pause = True elif pause: sleep(1)
ãã©ãã¯ããžãã¯
ç空äžã®çç¶ã®æªéã®ã¢ãã«ã次ã®ããã«è¡šçŸã§ããå ŽåïŒ
# -*- coding: utf-8 -*- class MyDaemon(object): def magic(self): # ....... def summon(self): # while True: self.magic() MyDaemon().summon()
ã³ã³ãããŒã«ããã«ã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£ ã¯ç°¡åã§ãã
# -*- coding: utf-8 -*- import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "web.settings") # control DJANGO_SETTINGS_MODULE # .. django.setup() from remotecontrol.control import * class MyDaemon(IRemoteControl): def magic(self): ....... def summon(self): while True: # self.check_commands() self.magic() MyDaemon().summon()
ãã®çµæãåŒã³åºãããæªéã¯å¶åŸ¡ãããŸããã管çããã«ããã®ã¿ã§ãã
ãã®ã³ãŒããdaemon.pyãªã©ã®ãã¡ã€ã«ã«å ¥ããŠãå ã«é²ã¿ãŸã-ã¢ãã€ã«ã¯ã©ã€ã¢ã³ããèšè¿°ããŸãã
REST API
ããããæåã¯ãã¢ãã€ã«ã¯ã©ã€ã¢ã³ããšãµãŒããŒåŽã®éã®éä¿¡çšã®ã€ã³ã¿ãŒãã§ã€ã¹ãå®è£ ããããšããå§ãããŸãã å§ããŸãããã
æºå段é
Django RESTãã¬ãŒã ã¯ãŒã¯ãã€ã³ã¹ããŒã«ããŸãã
æ¥ç¶ïŒweb \ settings.pyïŒïŒpip install djangorestframework
INSTALLED_APPS = [ ....... 'rest_framework', ]
ãããŠæ§æããŸãïŒåãå Žæã§ããã¡ã€ã«ã®æåŸã«è¿œå ããŸãïŒïŒ REST_FRAMEWORK = { # superuser' 'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',), # API, JSON 'DEFAULT_RENDERER_CLASSES': ('rest_framework.renderers.JSONRenderer',), }
ã·ãªã¢ã©ã€ã¶ãŒïŒremotecontrol \ serializers.pyïŒ
RESTã€ã³ã¿ãŒãã§ãŒã¹ã䜿çšããŠæ»ãããŒã¿ã»ãããèšè¿°ããããšããå§ããŸãã ããã§ã¯ãã¢ãã«èšè¿°ïŒ.status_dspïŒïŒããã³.code_dspïŒïŒïŒãããç¶æ ãšã³ãã³ãã³ãŒãã®ããã¹ãåãããããè¿ã䟿å©ãªç¥ç§çãªã¡ãœãããèŠã€ããŸãã
serializers.pyã®ãªã¹ãïŒ
from rest_framework import serializers from .models import Command class CommandSerializer(serializers.ModelSerializer): class Meta: model = Command fields = ('status', 'code', 'id', 'status_dsp', 'code_dsp', 'ip')
ããŒã¿ãã¥ãŒïŒremotecontrol \ views.pyïŒ
Djangoã¢ããªã±ãŒã·ã§ã³ã®ã¢ãŒããã¯ãã£ã®REST APIã¡ãœããã¯åããã¥ãŒã§ãããç解ã§ããã®ã¯âŠã ãã§ãã
ã¯ã©ã€ã¢ã³ããšéä¿¡ããã«ã¯
- commands_available-䜿çšå¯èœãªã³ãã³ãã³ãŒãã®ãªã¹ããšãã³ãã³ããåŠçããããšèŠãªãããã¹ããŒã¿ã¹ã³ãŒãã®ãªã¹ããè¿ããŸãã
- ã³ãã³ã -æ°ããã³ãã³ããªããžã§ã¯ããäœæããããã«äœ¿çšãããŸãã ããŒã¿ããŒã¹ã§äœ¿çšå¯èœãªãªããžã§ã¯ãã®ãªã¹ãã¯å¿ èŠãããŸããã
- ã³ãã³ã/ <ãªããžã§ã¯ãID> -ã³ãã³ããªããžã§ã¯ãã®ç¶æ ã決å®ããããã«äœ¿çšãããŸãã
ã³ãŒããæå°éã«æããããã«ãDjango RESTãã¬ãŒã ã¯ãŒã¯ã«ãã³ãã«ãããŠãããã³ã䜿çšããŸãã
- @api_view-é¢æ°ããŒã¹ã®ãã¥ãŒã®ãã³ã¬ãŒã¿ãŒããã©ã¡ãŒã¿ãŒã¯æå¹ãªhttpã¡ãœããã®ãªã¹ããæå®ããŸãã
- generics.CreateAPIView-ãªããžã§ã¯ããäœæããã¡ãœããã®ã¯ã©ã¹ã§ãPOSTã®ã¿ããµããŒãããŸãã
- generics.RetrieveAPIView-ãªããžã§ã¯ãã«é¢ãã詳现æ å ±ãååŸããããã®ã¯ã©ã¹ã§ãGETã®ã¿ããµããŒãããŸãã
views.pyã®ãªã¹ãïŒ
from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework import generics from ipware.ip import get_ip from .models import Command from .serializers import CommandSerializer @api_view(['GET']) def commands_available(request): # API- " " response = { # . CODE_REMOTE_OFF # , " " . 'commands': dict(Command.COMMAND_CHOICES), # , . 'completed': [Command.STATUS_DONE, Command.STATUS_DECLINE], } return Response(response) class CommandList(generics.CreateAPIView): # API- " " serializer_class = CommandSerializer def post(self, request, *args, **kwargs): # IP request.data[u'ip'] = u'' + get_ip(request) return super(CommandList, self).post(request, *args, **kwargs) class CommandDetail(generics.RetrieveAPIView): # API- " " queryset = Command.objects.all() serializer_class = CommandSerializer
ãšã³ããã€ã³ãïŒremotecontrol \ urls.pyïŒ
å®è£ ãããAPIã¡ãœããã®ãšã³ããã€ã³ãã«ã€ããŠèª¬æããŸãã
urls.pyã®ãªã¹ãïŒ
from django.conf.urls import url from . import views urlpatterns = [ url(r'^commands_available/$', views.commands_available), url(r'^commands/$', views.CommandList.as_view()), url(r'^commands/(?P<pk>[0-9]+)/$', views.CommandDetail.as_view()), ]
ãããŠãããããããžã§ã¯ãïŒweb \ urls.pyïŒã«æ¥ç¶ããŸãïŒ
urlpatterns = [ ....... url(r'^remotecontrol/', include('remotecontrol.urls')), ]
éä¿¡çšã®ã€ã³ã¿ãŒãã§ãŒã¹ãå®è£ ãããŠããŸãã ç§ãã¡ã¯æãããããã«æž¡ããŸãã
ããªã¢ãŒãã³ã³ãããŒã«ã¢ããªã
ãµãŒããŒãšéä¿¡ããã«ã¯ãUrlRequestïŒ kivy.network.urlrequest.UrlRequest ïŒã䜿çšããŸãã ãã¹ãŠã®å©ç¹ã®ãã¡ã次ã®ãã®ãå¿ èŠã§ãã
- éåæã¢ãŒãã®ãµããŒãã
- Python dictã«å¿ããŠæ£ããJSONãèªåçã«å€æããŸãã
å®è£ ãç°¡åã«ããããã«ãåºæ¬èªèšŒã¹ããŒã ã䜿çšããŸãã å¿ èŠã«å¿ããŠãUrlRequestã䜿çšããŠWebãªãœãŒã¹äžã®ä»ã®èªèšŒæ¹æ³ã«æ¬¡ã®èšäºã®ãããããåœãŠãããšãã§ããŸã-ã³ã¡ã³ããèšè¿°ããŸãã
main.pyã®ãªã¹ã
# -*- coding: utf-8 -*- import kivy kivy.require('1.9.1') from kivy.network.urlrequest import UrlRequest from kivy.properties import StringProperty, Clock from kivy.uix.button import Button from kivy.app import App from kivy.uix.boxlayout import BoxLayout try: from kivy.garden.xpopup import XError, XProgress except: from xpopup import XError, XProgress from json import dumps import base64 class RemoteControlUI(BoxLayout): """ """ # login = StringProperty(u'') password = StringProperty(u'') host = StringProperty('') def __init__(self, **kwargs): # ID self._cmd_id = None # "" self._completed = [] # . # "" # . self._wait_completion = False super(RemoteControlUI, self).__init__( orientation='vertical', spacing=2, padding=3, **kwargs) # self._pnl_commands = BoxLayout(orientation='vertical') self.add_widget(self._pnl_commands) # ============= http- ============== def _get_auth(self): # "Authorization" cred = ('%s:%s' % (self.login, self.password)) return 'Basic %s' %\ base64.b64encode(cred.encode('ascii')).decode('ascii') def _send_request(self, url, success=None, error=None, params=None): # headers = { 'User-Agent': 'Mozilla/5.0', 'Content-type': 'application/json', 'Authorization': self._get_auth() } UrlRequest( url=self.host + url, timeout=30, req_headers=headers, req_body=None if params is None else dumps(params), on_success=success, on_error=error, on_failure=error) # =========== =========== def _get_commands(self, instance=None): # API- "commands_available" self._progress_start('Trying to get command list') self._send_request( 'commands_available/', success=self._get_commands_result, error=self._get_commands_error) def _get_commands_result(self, request, response): # callback try: self._pnl_commands.clear_widgets() # for code, command in sorted( response['commands'].items(), key=lambda x: int(x[0])): btn = Button( id=code, text=command, on_release=self._btn_command_click) self._pnl_commands.add_widget(btn) self._completed = response['completed'] self._progress_complete('Command list received successfully') except Exception as e: self._get_commands_error(request, str(e)) def _get_commands_error(self, request, error): # callback self._progress_complete() XError(text=str(error)[:256], buttons=['Retry', 'Exit'], on_dismiss=self._get_commands_error_dismiss) def _get_commands_error_dismiss(self, instance): # callback if instance.button_pressed == 'Exit': App.get_running_app().stop() elif instance.button_pressed == 'Retry': self._get_commands() # ============= ============= def _btn_command_click(self, instance): # API- "commands" self._cmd_id = None self._wait_completion = True self._progress_start('Processing command "%s"' % instance.text) self._send_request( 'commands/', params={'code': instance.id}, success=self._send_command_result, error=self._send_command_error) def _send_command_result(self, request, response): # callback try: if response['status'] not in self._completed: # - ID self._cmd_id = response['id'] # , # if self._wait_completion: # Clock.schedule_once(self._get_status, 1) else: # self._progress_complete( 'Command "%s" is %s' % (response['code_dsp'], response['status_dsp'])) except Exception as e: XError(text=str(e)[:256]) def _send_command_error(self, request, error): # callback self._progress_complete() XError(text=str(error)[:256]) # ========== ========== def _get_status(self, pdt=None): # API- "commands/<id_>" if not self._cmd_id: return self._send_request( 'commands/%s/' % self._cmd_id, success=self._send_command_result, error=self._send_command_error) # ============= ============== def _progress_start(self, text): self.popup = XProgress( title='RemoteControl', text=text, buttons=['Close'], on_dismiss=self._progress_dismiss) self.popup.autoprogress() def _progress_dismiss(self, instance): self._wait_completion = False def _progress_complete(self, text=''): if self.popup is not None: self.popup.complete(text=text, show_time=0 if text is None else 1) # ========================================= def start(self): self._get_commands() class RemoteControlApp(App): """ """ remote = None def build(self): # self.remote = RemoteControlUI( login='test', password='qwerty123', host='http://localhost:8000/remotecontrol/') return self.remote def on_start(self): self.remote.start() # RemoteControlApp().run()
ããŸãããã°ãã³ãŒãå ã®ã³ã¡ã³ãã§ååç解ã§ããŸãã ããã§ãååã§ã¯ãªãå Žå-ç§ã«ç¥ãããŠãç§ã¯å€æŽãè¡ããŸãã
ãã®æç¹ã§ãã³ãŒãã®çããããçµäºããã·ãŒã³ã«å ¥ããŸã
éç ²
圌ã«ã€ããŠã¯ã»ãšãã©èªãããŠããªãã®ã§ãBuildozerã«ã€ããŠé·ãé話ãããšãã§ããŸãã Habréã«ã¯èšäºããããŸãïŒ ãªãªãŒã¹ããŒãžã§ã³ã® ã€ã³ã¹ããŒã«ãšæ§æ ã Google Playã§ã®å ¬éã«é¢ããèšäºïŒããã¡ããããã¥ã¡ã³ãããããŸã ...ããããããŸããŸãªãœãŒã¹ã«æ£ãã°ã£ãŠãã
ãã®é©ç°ã«å¯ŸåŠããããã®ããã€ãã®å®çšçãªãã³ãïŒ
- Androidã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããã«ã¯ããŸã Linuxãå¿ èŠã§ããä»®æ³ãã·ã³ã§å®è¡ã§ããŸãã , python-for-android ( ) sh ( pbs), Windows;
- , â Buildozer Android-dev . ( , ndk, sdk requirements) 30-40 ;
- Buildozer , Kivy Kivy-garden ( Kivy);
- , Buildozer ( â ). Buildozer , ( ) .
- Buildozer root;
ããŠãDebianãšUbuntuã®å¹žããªææè ãæ¯æŽããããã®å°ãã®ã³ãŒãïŒæ®ãã¯ããã¡ã€ã«ã§æ éã«åŠçãããå¿ èŠããããŸãïŒ
kivy-install.sh
# Create virtualenv virtualenv --python=python2.7 .env # Activate virtualenv source .env/bin/activate # Make sure Pip, Virtualenv and Setuptools are updated pip install --upgrade pip virtualenv setuptools # Use correct Cython version here pip install --upgrade Cython==0.20 # Install necessary system packages sudo apt-get install --upgrade build-essential mercurial git python-dev libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev libsmpeg-dev libsdl1.2-dev libportmidi-dev libswscale-dev libavformat-dev libavcodec-dev zlib1g-dev # Install kivy pip install --upgrade kivy
buildozer-install.sh
# Activate virtualenv source .env/bin/activate # Android SDK has 32bit libs sudo dpkg --add-architecture i386 # add system dependencies sudo apt-get update sudo apt-get install --upgrade ccache sudo apt-get install --upgrade libncurses5:i386 libstdc++6:i386 zlib1g:i386 sudo apt-get install --upgrade openjdk-7-jdk sudo apt-get install --upgrade unzip # Install buildozer pip install --upgrade buildozer
Buildozerãã€ã³ã¹ããŒã«ãããã®ã§ããããåæåããŸãïŒ
buildozer init
ãã®ã³ãã³ãã®çµæãã¢ã»ã³ããªãŒæ§æãã¡ã€ã«ïŒbuildozer.specïŒããã£ã¬ã¯ããªãŒã«äœæãããŸãã以äžã«ãªã¹ããããŠããããŒãèŠã€ããŠããããã«å¯Ÿå¿ããå€ãå²ãåœãŠãŸãã
buildozer.specã®ç·šé
# (list) Garden requirements
garden_requirements = xpopup
# (str) Supported orientation (one of landscape, portrait or all)
orientation = portrait
# (bool) Indicate if the application should be fullscreen or not
fullscreen = 0
# (list) Permissions
android.permissions = INTERNET
# (int) Minimum API required
android.minapi = 13
# (int) Android SDK version to use
android.sdk = 21
wunderwaffeãã¢ã¯ãã£ãã«ããŸãã
buildozer android debug
åºåã«ã¯.apkããããAndroidããã€ã¹ã«ã€ã³ã¹ããŒã«ã§ããŸãã
ã§ãã ããã§ãšãããããŸãïŒ
ãã¹ãäž
ãããŠãããããã¹ãŠã©ã®ããã«æ©èœããããèŠãŠã¿ãŸãããã圌ããããã»ã©é·ãéè©ŠããŠã¿ãã®ãäžæè°ã§ã¯ãããŸãã:)
DjangoãµãŒããŒãèµ·åããããŒã«ã«ãããã¯ãŒã¯äžã®ãã·ã³ã®IPããã©ã¡ãŒã¿ãŒãšããŠæå®ããŸãã
python manage.py 192.168.xxx.xxx:8000
ç§ãã¡ã¯æªéãšåŒã³ãŸãïŒ
python daemon.py
Androidããã€ã¹ã§ã¢ããªã±ãŒã·ã§ã³ãèµ·åãããšã次ã®ãããªãã®ã衚瀺ãããŸãã
泚ïŒgithubã«ãããããžã§ã¯ãã®æçµããŒãžã§ã³ã¯ããããªã®é²ç»ã«äœ¿çšãããŸãããæ©èœã®æ¡åŒµã«ãããèšäºã§æå®ãããã³ãŒããšã¯ç°ãªããŸãããŠãŒã¶ãŒã³ãã³ããšãããã°ã¡ãã»ãŒãžã®ãµããŒãããµãŒããŒããŒãã«è¿œå ããïŒããããããããããïŒãã¯ã©ã€ã¢ã³ãã«ã¯æ¿èªãã©ãŒã ãã³ãã³ãã®ç¢ºèªèŠæ±ãããã³ã€ã³ã¿ãŒãã§ã€ã¹ã®å©äŸ¿æ§ãè¿œå ãããŸããã
ãŸãšãããš
ãã®çµæãäœãåŸãããŸãããïŒ
- ãªã¢ãŒãã³ãã³ãã«å¯Ÿããåå¿ã®ããžãã¯ãå®è£ ããç°¡åã«åã蟌ã¿å¯èœãªã¯ã©ã¹ã
- Webã€ã³ã¿ãŒãã§ã€ã¹ããä»»æã®ã¹ã¯ãªãããå¶åŸ¡ããREST APIãæäŸãããµãŒããŒã¢ããªã±ãŒã·ã§ã³ã
- REST APIãä»ããŠã¹ã¯ãªããã管çããããã®Androidã¢ããªã±ãŒã·ã§ã³ã
ããŸãã«ã倧声ã§èšã£ããããããŸãããã... ç§ã¯è³ªåã«èŠãããããŠããŸã- ä»ã®èšèªãšæè¡ïŒPythonãé€ãïŒã䜿çšããŠåæ§ã®ã¢ãŒããã¯ãã£ãå®è£ ããïŒå°ãªããšãïŒãã以äžã®åŽåãšã³ãŒãã®èšè¿°ã¯äžå¯èœã§ããïŒ
以äžã§ãã
ãã¹ãŠã®çŽ æŽãããã³ãŒãã£ã³ã°ãšæåãããã«ãã
䟿å©ãªãªã³ã¯
githubã®ãRemoteControlInterfaceã
Djangoã®
ããã¯Django RESTãã¬ãŒã ã¯ãŒã¯ã®
ããã¯Kivyã®ããã¯
Kivyã®
ã€ã³ã¹ããŒã«Buildozerã®ã€ã³ã¹ããŒã«