catcutの日記

気ままに更新します。過去の制作物もそのうち公開します。

自炊

肉うどん

f:id:catcut:20230129205908j:image

豚細切れ肉150g

水 大2

みりん 大2

醤油 大2

酒 大2

砂糖 大2

本だし 小1

 

調味料混ぜて沸騰させて肉を突っ込む

水気がなくなるまで火にかける

 

うどん

カネスエの17円うどん

沸騰した水に突っ込んで2分にて水で締める

 

うどんつゆ

めんつゆ規定量

 

豆苗 適当

調理時間10分程度

fireHDで家計簿作成⑤ GoogleSpreadSheetをpythonで動かす

取り急ぎコードだけ

import gspread 
from oauth2client.service_account import ServiceAccountCredentials
import datetime
import json

class GSP_OPE():
    def __init__(self,\
    	 JsonPath = '/storage/emulated/0/Documents/python/project1/gsp_kakeibo.json',\
    	 SheetName = 'kakeibo',\
    	 DataLabel = ['購入日', '購入店', '商品名', 'カテゴリ', '重要度', '支払い方法', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', '登録日'],\
    	 LastUpdateLogPath = '/storage/emulated/0/Documents/python/project1/lastlog.txt',\
    	 SPREADSHEET_KEY = '10aZg3j9CaW_tLHEe3CsvJ8u64LXHDx6RRQ6z4aZWO9Y'):

        scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive']
        credentials = ServiceAccountCredentials.from_json_keyfile_name(JsonPath, scope) 
        gc = gspread.authorize(credentials)
        self.wks = gc.open_by_key(SPREADSHEET_KEY)

        #gc = gspread.service_account(filename = JsonPath)
        #self.wks = gc.open(SheetName)
        self.actv_sht = self.wks.worksheet('data')
        self.wks_data = self.wks.worksheet('data')
        self.wks_ddl  = self.wks.worksheet('dropdownlist')
        self.logfile  = LastUpdateLogPath
        self.data_lb = DataLabel
    
    def target_sheet(self, target_sheet_str = None, target_sheet_num = None):
        if target_sheet == None and target_sheet_num == None: return 'error 0000'
        if target_sheet_str != None and target_sheet_num == None:
            try:
                self.actv_sht = self.wks.worksheet(target_sheet_str)
                return 'change'
            except:
                return 'error0002'
        if target_sheet_str == None and target_sheet_num != None:
            try:
                self.actv_sht = self.wks.get_worksheet(target_sheet_str)
                return 'change'
            except:
                return 'error 0004'
        if target_sheet_str != None and target_sheet_num != None: return 'error 0006'
    
    def serch_row(self, target_word = None, target_column = None, serch_last_row_flag = False, last_update_row = 1): #return the number of row
        if target_word == None and target_column == None and serch_last_row_flag == False:
            return 'error 0020'
        elif target_word != None and target_column == None:
            return 'error 0040'
        elif target_word != True and serch_last_row_flag == True:
            return 'error 0060'
        
        """    unimprement
        if target_word <> None and target_column == None:    #WS.cell(row, col).value    row,col >= 1
            row = 1
            break_flag = False
            while(1):
                max_col = self.serch_column(target_row = row, last_update_column = True)
                if mac_col == 0: return [row, 0]
                for col in range(1, max_col + 1): 
                    if self.actv_sht.cell(row, col).value == target_word: return [row, col]
                row = row + 1
         """
         
        row = last_update_row                
        if target_word != None and target_column != None:
            while(1):
                if self.actv_sht.cell(row, target_column).value == target_word: return [row, target_column]
                if self.actv_sht.cell(row, target_column).value == None: return [0, 0]
                row = row + 1
        if serch_last_row_flag == True and target_column != None:
            while(2):
                if self.actv_sht.cell(row, target_column).value == None: return [row, target_column]
                row = row + 1
        if serch_last_row_flag == True:
            while(3):
                if self.actv_sht.cell(row, len(self.data_lb)).value == None: return [row, 0]
                row = row + 1
        return  'error 0080'
                  
    def serch_column(self, target_word = None, target_row = None, serch_last_column_flag = False, last_update_column = 1): #return the number of row
        if target_word == None and target_row == None and serch_last_column_flag == False:
            return 'error 0200'
        elif target_word != None and target_row == None:
            return 'error 0400'
        elif target_word != True and serch_last_column_flag == True:
            return 'error 0600'
        
        col = last_update_column        
        if target_word != None and target_row != None:
            while(1):
                if self.actv_sht.cell(target_row, col).value == target_word: return [target_row, col]
                if self.actv_sht.cell(target_row, col).value == None: return [0, 0]
                col = col + 1
        if serch_last_column_flag == True and target_row != None:
            while(2):
                if self.actv_sht.cell(target_row, col).value == None: return [target_row, col]
                col = col + 1         
        return    'error 0800'                
    
    def write_data(self, row = 1, column = 1, data = "write"):
        self.actv_sht.update_cell(row, column, data)
        
    def read_data(self, row = 1, column = 1, data = "write"):
        return self.actv_sht.cell(target_row, col).value

    def write_array(self, row = 1, column = 1, arr = [['w','r'],['i','g'],['t','!']]):
        for n in range(len(arr)):    #row
            for m in range(len(arr[n])):    #column
                self.actv_sht.update_cell(row + n, column + m, arr[n][m])
        
    def read_array(self, row1 = 1, row2 = 5, column1 = 1, column2 = 5):
        buf = [[]]
        for n in range(row1, row2 + 1):
            buf2 = []
            for m in range(column1, column2 + 1):
                buf2.append(self.actv_sht.cell(n, m).value)
            buf.append(buf2)
        buf.pop(0)
        return buf
    
    def save_log(self, arr):
        with open(self.logfile, "a") as f:
            writer  = f.write(datetime.datetime.now(JST).strftime('%Y/%m/%d') + '::' + str(arr) + '\n')
    
    def serch_word(self, serch_word = '1'):
        return self.actv_sht.find(serch_word)
        
    def get_all_val_row(self, row= 1):
        return self.actv_sht.row_values(row)
        
    def get_all_val_col(self, col= 1):
        return self.actv_sht.col_values(col)
    
def main():
    gsp  = GSP_OPE()
    gsp.write_data(row = 2, column = 1, data = "write")
    print('ok')
    gsp.write_array(row = 2, column = 2, arr = [['w','r'],['i','g'],['t','!']])
    print('ok2')
    print(gsp.read_array(row1 = 2, row2 = 6, column1 = 1, column2 = 6))

if __name__ == "__main__":
    main()

fireHDで家計簿作成④ 記録するもの

google spread sheetには

購入日

購入店

商品名

カテゴリ

重要度

支払い方法

登録日

を記録する。日付以外はドロップダウンリストを作りたい。

登録日は確実に登録されるため、チェック用に使用する。

項目を追加する可能性があるため、登録日は15列目あたりに記載する。

 

sheet1にはデータを羅列する。

sheet2にはGUI表示用のドロップダウンリストを作成する。

 

データ量が膨大になった時に最終行を探すのが大変なため、ログファイル(.txt)をローカルに残す。

このログファイルには最終更新の行と投稿時間を記録する。

 

gsp操作のプログラムはオブジェクト指向っぽくかく。

インスタンス化する時に

jsonファイルを使って認証する。

各シートも変数としてわかりやすくする。

タグも定義しとく。

データログのパスも定義しとく。ついでに最終更新行も取得しとく。

 

メソッドはとりあえず

モード選択

アクティブシートの変更

行を検索してその番号を返す

列を検索してその番号を返す(使わないかも)

特定のワードのセルを返す

指定したセルに書き込む

指定したセルを読み込む

範囲指定したセルを読み込み配列で返す

範囲指定したセルと受け取った配列を書き込む

データログに保存する

シートを保存する

シートを閉じる

を用意する。

 

 

行を検索するメソッド

引数 

検索ワード

検索列

最終行取得フラグ

最終更新行

 

処理パターン1:

検索ワードと検索列が与えられる

処理パターン2:

最終行取得フラグと検索列が与えられる

処理パターン3:

最終行取得フラグが与えられる

エラーパターン:

検索ワードと最終行が同時に与えられる

検索ワードと検索列のいずれかのみ与えられる

ー検索列と最終行フラグが両立するので、検索ワードがあって検索列が無いパターンのみエラー処理

何も与えられない

 

 

【息抜き】ハード食パン作成中

参考

recipe.cotta.jp

分量を調整

強力粉… 365g

ドライイースト… 3g
モルトパウダー… 3g
砂糖… 7g
塩… 7g
水… 250g
無塩バター… 10g

 

↓強力粉

f:id:catcut:20230108143234j:image

ドライイースト

f:id:catcut:20230108143329j:image

モルトパウダー

f:id:catcut:20230108143417j:image

 

混ぜる順番と捏ね時間、発酵時間はレシピ通りに行った。一次発酵が少々過発酵だったかも知れない。

モルトパウダーは水(分量内)で溶かして投入した。

水の温度は40℃程度に調整した。

ドライイーストと塩は離して投入した。

砂糖の上にドライイーストを乗せた。

 

発酵温度は室温発酵で25〜28℃

オーブンの発酵機能で35℃

 

生地がベタついた。

スキムミルク入ってないからかな?

水の量をもっと減らしてもいいのかも知れない。

 

モルトパウダーも多すぎたのかな?

 

↓発酵途中

f:id:catcut:20230108143821j:image

↓30分後

f:id:catcut:20230108161158j:image

↓焼き上がり(油足りなくてくっついちゃった)

f:id:catcut:20230108161233j:image

f:id:catcut:20230108161248j:image

fireHDで家計簿作成③ fireHDでTkinter

アンドロイドVNCをいれました。
無料なのにタッチ操作が割りと快適だからです。
暫定の画面

以下ソースコード
termuxで実行してアンドロイドVNCで覗く。

import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
import sys

class Sizeset():
    
    """
    fo = {'font' : 'times new roman', 'size' : 18, 'tickness' : 'bold'},\
    	wt = 200, hg = 100,\
    	fc = 'green',\#FontColor
    	fg = 'green',\#ActiveFontColor unimplemented
    	bg = 'black',\#not ActiveBackColor
    	ag = 'blue',\#ActiveBackColor
    	ac = 'w', 'nw', 'n', 'ne', 'w', 'e', 'sw', 's', 'se', 'center'
    	jf = tk.CENTER ,tk.LEFT, tk.RIGHT 
    	rf = relief:'flat', 'raised', 'sunken', 'groove', 'ridge', 'solid'
    """
    
    def __init__(\
    	self,\
    	fo = {'font' : 'times new roman', 'size' : 18, 'tickness' : 'bold'},\
    	wt = 200, hg = 100,\
    	fc = 'green',\
    	fg = 'green',\
    	bg = 'black',\
    	ag = 'blue',\
    	ac = 'center',\
    	jf = tk.CENTER,\
    	rf = 'sunken'\
    	):
        self.__FontOption   = fo
        self.__Width        = wt 
        self.__Height       = hg
        self.__FontColor    = fc
        self.__ActiveFontColor = fg
        self.__BackGround   = bg
        self.__ActiveBackGround = ag
        self.__Anchor       = ac
        self.__Justify      = jf
        self.__Relief         = rf

    def fontoption(self):
        return self.__FontOption
    def width(self):
        return self.__Width
    def height(self):
        return self.__Height
    def fontcolor(self):
        return self.__FontColor
    def activefontcolor(self):
        return self.__ActiveFontColor
    def frontcolor(self):
        return self.__BackGround
    def backcolor(self):
        return self.__ActiveBackGround
    def anchor(self):
        return self.__Anchor
    def justify(self):
        return self.__Justify
    def relief(self):
        return self.__Relief
    
class OyaFrame(tk.Frame):
    def __init__(self, master = None):
        super().__init__(master)
        """
           fc = 'black',\#FontColor
        	  fg = 'black',\#ActiveFontColor
        	  bg = 'green',\#not ActiveBackColor
        	  ag = 'blue',\#ActiveBackColor
        	  ac = 'w',\#Anchor
        	  jf = tk.CENTER,\#Justify
        	  rf = 'SUNKEN'#relief
        """
        self.monitor_height = self.master.winfo_screenheight()
        self.monitor_width = self.master.winfo_screenwidth()    
        self.master.geometry(str(self.monitor_width)+'x'+str(self.monitor_height-50))
        
        BS = Sizeset(fo = {'font' : 'times new roman', 'size' : 48, 'tickness' : 'normal'},\
        	  wt = self.monitor_width / 3, hg = self.monitor_height / 6 ,\
        	  fc = 'black',\
        	  fg = 'black',\
        	  bg = 'green2',\
        	  ag = 'green3',\
        	  ac = 'center',\
        	  jf = tk.CENTER,\
        	  rf = 'sunken'\
        	  )
        #style = ttk.Style()      
        #style.configure('office.TButton', font=20, anchor='w')

        #print(self.monitor_height,self.monitor_width)
        #self.master.geometry('1920x1080') 
        # ボタンの作成
        Button_Text = ['登録', '修正', '解析', '終了']
        Button_Command = {0:self.Button0, 1:self.Button1, 2:self.Button2, 3:self.Button3} 
        self.button = []
        for n in range(len(Button_Text)):
            self.button.append(tk.Button(self.master,\
            	 text = Button_Text[n],\
            	 fg = BS.fontcolor(),\
            	 activeforeground = BS.activefontcolor(),\
            	 bg = BS.frontcolor(),\
            	 activebackground = BS.backcolor(),\
            	 font=(BS.fontoption()['font'], BS.fontoption()['size'], BS.fontoption()['tickness']),\
            	 anchor = BS.anchor(),\
            	 justify = BS.justify(),\
            	 relief = BS.relief(),\
            	 command = Button_Command[n]
            	 ))
            self.button[n].place(x = self.monitor_width/10,\
            	 y = self.monitor_height / 8 + (BS.height() * 1.1) * n ,\
            	  width = BS.width(), height =BS.height())
        print(len(self.button))
        
    #Button Comand
    def Button0(self):    #resistor
        messagebox.showinfo('event', 'Button0 was Pushed!')
        print('Button0 was Pushed!')
    
    def Button1(self):    #revise
        messagebox.showinfo('event', 'Button1 was Pushed!')
        print('Button1 was Pushed!')
    
    def Button2(self):    #analysis
        messagebox.showinfo('event', 'Button2 was Pushed!')
        print('Button2 was Pushed!') 
    
    def Button3(self):    #close
        messagebox.showinfo('event', 'Button3 was Pushed!')
        self.master.destroy()
        sys.exit()

def main():
    root = tk.Tk()
    app = OyaFrame(master = root)
    app.mainloop()

if __name__ == "__main__":
    main()

キャッシュ溜まったら
pip cache purge

fireHDで家計簿作成②

*termuxにはデスクトップの環境設定がない。

設定する必要がある。

 

**まずVNCをインストールする。

以下のコマンドを入力する。

pkg install x11-repo
pkg install tigervnc

 

**VNCサーバーを起動する。

以下のコマンドを入力する。

 

vncserver

または

vncserver :1 -geometry 1280x720

vncserver :1 -geometry 1920x1080

 

***※補足

稼働中のvncserverの確認は以下のコマンドを入力する。

vncserver -list

vncserverを停止するには以下のコマンドを入力する。

vncserver -kill :1

 

**環境変数Localhostの番号を設定する 。

export DISPLAY=":1"

 

**Window Managerを入れる。

以下のコマンドを入力する。

pkg install twm
pkg install aterm

 

**VNCサーバーの待機ポートを確認 

localhost:1だったら「5901」になる。


※参考

デフォルトでは、VNCサーバーはTCPポート5900 + nでVNCビューアからの接続を待機します。ここで、nはディスプレイ番号です(通常は0)。つまり、VNCサーバーのディスプレイ番号が0の場合はTCPポート5900で、ディスプレイ番号が1の場合はTCP-5901で通信します。使用するファイアウォールのドキュメントを参照して、これらのポートが開放されていることを確認してください。

docs.citrix.com

 

vncviewerをインストールしてログインする。

vncviewerのapkをどっかから調達する。

 

fireHDで家計簿作成① FireHD用家計簿ソフト作成の原案

Python 使えるようにしたし、家計簿ソフトでも作ろうかな。
Termaxで起動する。
データはgoogle spread sheetに蓄積させる。他の機器からもアクセスできるようにするため。
FireHDから直接編集できないためgoogl spread sheetのライブラリを使用する。

データは下の通り
日付   購入日(2022/01/01)等と入力
購入店  店の名前
商品名  適当に
カテゴリ 食品、衣料品、雑貨他
重要度  段階 0:無くてもいい 1:あったら便利 2:必要不可欠
登録日  登録した日


モード選択[登録]→登録画面
モード選択[修正]→修正モード画面→日付指定で情報表示画面→上書きモード画面
モード選択[解析]→解析モード画面→解析モード[随時追加予定]

GUITkinter で作成する。
モード選択画面

登録画面

情報表示画面

上書きモード画面


情報表示画面では日付を指定して表示を押すとドロップダウンリストに一覧が出てくる。
情報を選んで修正を押すと上書きモード画面モードへ。
詳細はまた練ろうかな。