Raspberry Pi 3's OS for server use
raspberry pi 3でwebサーバーとファイルサーバーを建てようと思っており、サーバーと言えばCentOSというネットの情報とCentOS 7になって少し仕様が変わったらしいけど新しく始めるなら新しいものからという自分の信条よりラズパイにCentOS 7を入れてみました。
入れたはいいもののwifiの設定をするにはgitで関連するレポジトリをクローンで持ってくる必要があり、gitの導入にはyumコマンドを使う必要があるのにデフォルトではyumを使うとエラーが出るという壁に当たりました。CentOS 7@ras-piでyumアップデートをするとエラーが出るという症状はどうやら他の方も出ているようです。
参考URLの方では解決策も提示してくれているのですが、自分の環境ではyumのエラーは解決しませんでした。試行錯誤しつつ数日経った後、あるネット記事にたどり着きました。
参考2 d.hatena.ne.jp
タイトルと自分が今まで調べた情報より「CentOSおすすめ記事か」などと思い読み進めてみるとどうも様子がちがうようで、世界的に見ればサーバーOS@Linuxとして覇権を握ったのはubuntuのようです。CentOSのシェアが下がったというよりはubuntuの人気が上がったのかなと思います。
参考3 srad.jp
こんな記事もあるので単純に参考2の記事を信頼するのも考えものですが、しかし流行っているものが今後も使われるというのは確かに一理あるとも思われるのでサーバーOSとしてのubuntuの立ち位置はこのまま続くのではないかと自分で判断しました。
というわけでCentOSのインストールはやめ、ubuntu MATEをラズパイにインストールしました。
ubuntu MATE(マテと読むみたいです。スペイン語らしいですね。自分はずっとメイトとよんでいました。)はGNOME 2からフォークされたデスクトップ環境MATEを用いたubuntuでラズパイ用のOSもあります。純粋なサーバーOSではないですが個人が趣味で建てるサーバーなのでインストールと設定の簡便さを優先しました。後ほどデスクトップ環境をアンインストールしてしまえばいいと思ったのもあります。
インストールの手順については色々なブログ等で紹介されているので割愛しますが、インストールしてからの驚きがすごいですね。
まず、設定がGUIなので楽ですね(デスクトップOSなので当たり前ですが)。設定が終わって有線LANを外すとそれだけでwifiが使えるようになってました(初期設定もwifiだけでいけたかもしれないです。)文章で書くとそこまででもないかもしれないですが、wifiを使えるようにするためだけに数日本気で悩んだ自分としてはこれだけでも感動モノでした。
さらに、CentOSではデフォルトでnanoエディタが入っておらず、今まで使ったことのなかったvimエディタで様々な設定をするしかありませんでした(vim自体は高機能なエディタですし、結果として使えるようにすることは損ではなかったのですが)。しかもCentOSのviはvim-tinyとかよばれるもので設定も最小限のものしかなく、yumが使えずvim-enhancedがインストールできなかった自分には辛いものがありました。
一方でubuntu MATEではデフォルトはnanoを使うことが推奨されているようでvim系はvim-tinyがインストールされていたのですが、apt-getでvimをインストールしてhello worldプログラムをC言語で書いてみるとすでにシンタックスハイライトがONになってるじゃないですか!CentOSでもvimをインストールできたらもとからシンタックスハイライトが使えるようになっていたのかもしれないですけど、インストールする段階にまでたどり着けなかったので…
さすがubuntu系は様々なところで至れりつくせりだなーとしみじみ思いました。
正直インストールしたてであまりいじってないのでこのぐらいしか書くことがないのですが、この感動をなにか文として残しておきたかったので書いてみました。思った以上に長文になってしまいました。それでは。
limitlessledその4
limitlessledについての記事は4つ目となります。またしてもlimitlessledの操作をGUIアプリから行おうといういつもどおりの記事です。
前回、前々回もPyQtとledcontrollerを用いてGUIアプリを作成したのですが、コードの読みにくさや冗長な部分があったり、車輪の再発明をしており最適なコードとは言えないものでした。それらを今の段階において改良したものが下記のコードになります。
簡単に前回のコードとの違いを列挙すると、
- オブジェクト指向プログラミングに則ってGUIのパーツ毎にクラスを定義し、MainWindowクラスに多くのコードを持たせない。
- タイマー機能をthreadingライブラリのthreadよりサブスレッドを生成しfor文とtime.sleep()関数によって実装していたところをPyQt.QTimerによって実装した。
またデザイン面では
- タイマーの残り時間をプログレスバーで表記していたところを数字での表記に変更した。
ことが挙げられます。
コードの違いに関しては2つとも保守性の向上が期待できると考えています。 デザイン面の変更はプログレスバーのパーセント表記のためにわざわざ残り時間を選択された時間で割ってやる手間を省きたかったからです。
大きな変更はこの3つぐらいですかね。以下にコードを載せます。
# -*- coding: utf-8 -*- """ Created on Sun Mar 26 21:54:31 2017 @author: ujair """ import sys import PyQt4.QtGui as gui import PyQt4.QtCore as core import ledcontroller as led import time as TIME IP = '192.168.xx.xxx' LED = led.LedController(IP, group_1='white', group_2='white', group_3='white', group_4='white') class UI(gui.QMainWindow): def __init__(self): super().__init__() def initUI(self): #============================== # begin menu bar #============================== exitGUI = gui.QApplication.style().standardIcon(gui.QStyle.SP_TitleBarCloseButton) exitAction = gui.QAction(exitGUI, 'Quit LimitlessLED', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Exit application') exitAction.triggered.connect(gui.qApp.quit) menubar = self.menuBar() fileMenu = menubar.addMenu('LimitlessLED') fileMenu.addAction(exitAction) menubar.setNativeMenuBar(False) #============================== # end menu bar #============================== g1 = group_box1() g2 = group_box2() #============================== # begin HBOX1 #============================== on = gui.QPushButton('ON', parent = self) on.clicked.connect(LED.on) off = gui.QPushButton('OFF', parent = self) off.clicked.connect(LED.off) HBOX1 = gui.QHBoxLayout() HBOX1.addStretch(1) HBOX1.addWidget(on) HBOX1.addWidget(off) #============================== # end HBOX1 #============================== VBOX = gui.QVBoxLayout() VBOX.addWidget(g1) VBOX.addWidget(g2) VBOX.addLayout(HBOX1) widget = gui.QWidget() widget.setLayout(VBOX) self.setCentralWidget(widget) self.setGeometry(0, 0, 300, 300) self.show() class time: def __init__(self, sec = 0): self.sec = sec self.set_sec(sec = self.sec) def get(self): return (self.h, self.m, self.s) def decrement(self): self.sec -= 1 self.set_sec(sec = self.sec) def set_sec(self, sec = 0): self.sec = sec self._h(self.sec) self._m(self.sec) self._s(self.sec) def _h(self, sec): self.h = int(sec/3600) def _m(self, sec): self.m = int((sec%3600)/60) def _s(self, sec): self.s = int(sec%60) class group_box1(gui.QGroupBox): def __init__(self): super().__init__('Timer') self.cancel = False self.countdown = 0 self.progress = 0 self.time = time() self.flag = False #============================== # begin hbox1 #============================== self.display = gui.QLabel("{0:01d}:{0:02d}:{0:02d}".format(0, 0, 0), parent = self) self.display.setFont(gui.QFont("Menlo", 80)) self.display.setAlignment(core.Qt.AlignRight) hbox1 = gui.QHBoxLayout() hbox1.addWidget(self.display) #============================== # end hbox1 #============================== #============================== # begin hbox2 #============================== times = gui.QComboBox(parent = self) times_text = ['30', '60', '90', '120'] times.addItems(times_text) times.activated[str].connect(self._times_activate) cancel = gui.QPushButton('cancel', parent = self) cancel.clicked.connect(self._stop) hbox2 = gui.QHBoxLayout() hbox2.addWidget(times) hbox2.addStretch(1) hbox2.addWidget(cancel) #============================== # end hbox2 #============================== vbox1 = gui.QVBoxLayout() vbox1.addLayout(hbox1) vbox1.addLayout(hbox2) self.setLayout(vbox1) def _times_activate(self, text): print(TIME.ctime()) minutes = int(text) self.time.set_sec(sec = minutes*60) self.display.setText("%01d:%02d:%02d" % self.time.get()) self.countdown = minutes*60 self.flag = True self.timer = core.QTimer() self.timer.setInterval(1000) self.timer.timeout.connect(self._countdown_time) self.timer.start() def _countdown_time(self): self.countdown -= 1 self.time.decrement() self.display.setText("%01d:%02d:%02d" % self.time.get()) if(self.countdown <= 0 and self.flag == True): LED.off() self._stop() def _stop(self): self.timer.stop() self.countdown = 0 self.time.set_sec(sec = 0) self.display.setText("%01d:%02d:%02d" % self.time.get()) self.flag = False class group_box2(gui.QGroupBox): def __init__(self): super().__init__('Cool and Warm') #============================== # begin hbox1 #============================== warm = gui.QPushButton('Warm') warm.clicked.connect(LED.warmer) cool = gui.QPushButton('Cool') cool.clicked.connect(LED.cooler) hbox1 = gui.QHBoxLayout() hbox1.addStretch(stretch = 1) hbox1.addWidget(warm) hbox1.addStretch(stretch = 1) hbox1.addWidget(cool) hbox1.addStretch(stretch = 1) #============================== # end hbox1 #============================== self.setLayout(hbox1) def main(): app = gui.QApplication(sys.argv) ui = UI() ui.initUI() sys.exit(app.exec_()) if __name__ == '__main__': main()
前回も書いたかもしれませんが、limitlessledのデュアルホワイトモデルを購入したためLEDの指定方法として
group_1 = 'white'
というような書き方をしています。
実際に起動すると以下のような画面になります。
まだまだ未熟ですが一番最初につくったときからはだいぶ進化していると自分では思っています。 よい実装が思いついたらまた改良していきたいと思います。
それではこのへんで。
キーワード付き引数におけるpandas DataFrameの扱い
pandasのDataFrameをキーワード付き引数として渡したいときについてです。タプルやリストは
def func(tup = None, li = None): if(tup != None): print(tup) if(li != None): print(li)
のような関数を定義してもエラーは出ません。しかし、
def func2(df = None): if(df != None): print(df)
として引数としてpandasのDataFrameを渡してやると下記のようなエラーが出ます。(ちなみにfunc2にタプルやリストを渡してもエラーは出ません)
TypeError: Could not compare [None] with block values
いつもながらgoogle先生に聞いてみると英語情報ですが同じ質問をしている方がおられました。
要約すると比較演算子
!=
じゃなくて
is not
を使えと書かれてます。
詳しい説明の方も読もうかと思ったのですが、あんまり良くわからなかったので分かる方はぜひ読んでみてください。
limitlessledその3
PythonでGUIプログラミングをするときはだいたいPyQtを使っています。あまり使い慣れていないということもありまして一つのGUIプログラムを作るのに非常に時間がかかっていたのですが、この前いじっているときにようやっとコツを掴んだというか理解したのである程度のものは作れるようになりました。
そこで前々から作ろうと思っていたlimitlessledのタイマーを作ったので公開してみようと思います。
まず、自分の環境についてですが
- macOS Sierra 10.12.3
- anaconda3-4.1.0
です。どこまで環境を書けばいいのかわからないのですが、もう少し詳しく書くと、まずmacにhomebrewを入れて、その後pyenvを入れました。pyenvからanacondaを入れました。anacondaにはPyQtが標準で入ってたはずですが、入っていなければ
conda install pyqt4
とかでインストールできると思います。なので、あとはlimitlessledのPythonライブラリであるledcontrollerのインストールのみで自分のプログラムは起動できるはずです。ledcontrollerのインストールは上記のように
conda install ledcontroller
でいけるはずです。
あとanacondaのPATHなんかは通しておいてください。
実際のプログラムは以下になります。
# -*- coding: utf-8 -*- import sys import PyQt4.QtGui as gui import PyQt4.QtCore as core import ledcontroller as led import time import threading as th IP = 'xxx.xxx.xx.xx' LED = led.LedController(IP, group_1='white', group_2='white', group_3='white', group_4='white') class UI(gui.QMainWindow): def __init__(self): super().__init__() self.cancel = False self.progress = 0 def initUI(self): exitGUI = gui.QApplication.style().standardIcon(gui.QStyle.SP_TitleBarCloseButton) exitAction = gui.QAction(exitGUI, 'Quit Milight', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Exit application') exitAction.triggered.connect(gui.qApp.quit) menubar = self.menuBar() fileMenu = menubar.addMenu('Milight') fileMenu.addAction(exitAction) menubar.setNativeMenuBar(False) #group_box1 #hbox1 tim = gui.QComboBox(parent = self) tim.activated[str].connect(self._activate) times = ['30', '60', '90', '120'] tim.addItems(times) cancel = gui.QPushButton('cancel', parent = self) hbox1 = gui.QHBoxLayout() hbox1.addWidget(tim) hbox1.addStretch(1) hbox1.addWidget(cancel) #hbox2 self.pbar = gui.QProgressBar(parent = self) self.percentage = gui.QLabel('0%', parent = self) def stop_progress(): self.cancel = True cancel.clicked.connect(stop_progress) hbox2 = gui.QHBoxLayout() hbox2.addWidget(self.pbar) hbox2.addWidget(self.percentage) vbox1 = gui.QVBoxLayout() vbox1.addLayout(hbox1) vbox1.addLayout(hbox2) group_box1 = gui.QGroupBox('Timer', parent = self) group_box1.setLayout(vbox1) #group_box2 warm = gui.QPushButton('Warm') warm.clicked.connect(LED.warmer) cool = gui.QPushButton('Cool') cool.clicked.connect(LED.cooler) hbox3 = gui.QHBoxLayout() hbox3.addWidget(warm) hbox3.addWidget(cool) group_box2 = gui.QGroupBox('Cool and Warm') group_box2.setLayout(hbox3) on = gui.QPushButton('ON', parent = self) on.clicked.connect(LED.on) off = gui.QPushButton('OFF', parent = self) off.clicked.connect(LED.off) hbox4 = gui.QHBoxLayout() hbox4.addStretch(1) hbox4.addWidget(on) hbox4.addWidget(off) Gbox = gui.QVBoxLayout() Gbox.addWidget(group_box1) Gbox.addWidget(group_box2) Gbox.addLayout(hbox4) w = gui.QWidget(parent = self) w.setLayout(Gbox) self.setCentralWidget(w) self.setGeometry(100, 150, 250, 250) self.setWindowTitle('Milight') self.show() def _activate(self, text): print(time.ctime()) minutes = int(text) self.cancel = False thread1 = th.Thread(target=self._ti, args =(minutes,)) thread1.start() def _ti(self, minutes): for i in range(minutes*60): if(self.cancel): break; self.progress = (i+1)/(minutes*60)*100 time.sleep(1) self.pbar.setValue(self.progress) self.percentage.setText('{}%'.format(round(self.progress))) if(not self.cancel): LED.off() self.pbar.setValue(0) self.percentage.setText('0%') def main(): app = gui.QApplication(sys.argv) ui = UI() ui.initUI() sys.exit(app.exec_()) if __name__ == '__main__': main()
IPと書かれているところはlimitlessledのwi-fiブリッジのIPアドレスを入力してください。自分は固定IPを振っています。あと新しくlimitlessled dual whiteを購入してそちらを使っているので一番最初の
LED = led.LedController(IP, group_1='white', group_2='white', group_3='white', group_4='white')
のところで
group_x = 'white'
としています。この前で使っていたRGBWの方はこのような引数を与える必要はなかったのですがdual whiteでは必要になるようです。 環境さえ整えばmacじゃなくてもlinuxやwindowsとかでも動くんじゃないかなと思います。 あと不具合というほどのことでもないのですが、自分の環境ではこのプログラムを起動して最前面にしておかないとTimerが動いてくれない時があります。
初めてまともなGUIを自分で組めました。わりと達成感がありますね。これからも色々作っていけたらいいなと思います。
起動したときのスクショは以下のようになります。
マルチスレッド
いつもながらPythonのことを。
limitlessled用のプログラムをPythonで組んだ(ここらへんのくだり)のですが、微妙に使いづらくあまり使っていません。というのもタイマーで何分後にオフみたいな設定をtime.sleep()で実装しているので、実際sleepしている間他の操作を受け付けなくなるんですよね。自分だけしか使わないのでそれでもいいのですが、できれば他の操作を受け付けるとかキャンセルボタンでタイマーをキャンセルするとかできると便利だな−と思ってました。
マルチスレッド機能が使えれば待ち時間も他の操作を受け付けることができるなと思い出して色々調べていたのですが、なかなか理解できません……
プログラム自体はPyQtを使っているのでQThreadを使おうかと思ってみても、日本語のチュートリアルが少ない…… そもそもPythonを始めたきっかけのマイナビニュースのサイトを見るとthreadingライブラリを使っているので、こっちを使ってみるべきなんですかね。
イマイチPyQtにもなれていないので、更に新しいことをやろうとするとつまづきが多くて戸惑ってしまいますね。
久しぶりに書いた割になんの進歩もしていないのですが、こんな感じですかね。
あと全然関係ないですが、raspberry pi 3を買おうと思ってます。一応Airでもfedoraが使えるようにはしてあるんですが、Linux専用機があったほうがLinuxは使うなと思いまして。しかも電子工作みたいなこともできるらしく、ちょっとしたロボットとか作ってみたいなーと思ってます。そこまで行くのにどんだけ勉強せなならんのかという感じですが。official starter kitがほしいんですよね−。薄型の有線キーボードなかなか売ってないので…あと統一感があっていいなと思います。rs onlineで買おうと思ったら個人相手にやってないそうなので、海外でもcana kitの方で買いますかね。
ではではこのへんで。