ラズパイ5 2023年10月更新 bookworm ⑥ CPUの温度を4桁7セグメントLED表示器に

　ラズパイ4を用いた＜[ラズパイ 2023年10月更新 bookworm　連載記事](https://www.denshi.club/parts/2024/02/202310-bookworm-6-cpu.html)＞をラズパイ5で再検証した記事です。

 　[前回](https://qiita.com/jamjam/items/c9b76e7c6a36feea030a)、I2Cバスに接続した4桁7セグメントLED表示器に、室温を表示しました。ここでは、ラズパイ本体のCPUの温度を表示します。
  
  ![IMGP2095.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/543ff047-a71f-7f1e-521f-01c618839559.png)
  
### CPU温度の取得

```shell
$ vcgencmd measure_temp

temp=37.4'C
```

　pythonで実行して、温度を取得します。subprocessライブラリを利用します。

　最初に、subprocess.check_output()関数を使います。結果はbyte列で受け取るので、デコードします。

```python
proc = subprocess.check_output('vcgencmd measure_temp',shell=True )

print(proc.decode())
```

`temp=37.0'C`

が得られます。

　調べると、subprocess.run()関数を利用するほうが良いような記述が出てきたので実行します。

```python
proc = subprocess.run('vcgencmd measure_temp',shell=True, capture_output=True, text=True)
```


　実行結果はデコードされて.stoutで得られます。

```python
print(proc.stdout)
```

`temp=37.0'C`

　温度の数値が欲しいので、'='で分離します。

```python
print(proc.stdout.split('='))

['temp', "37.0'C\n"]
```

　後ろ側を取り出します。

```python
print((proc.stdout.split('='))[1])
```

`37.0'C`

　’’’で分離します。


```python
print(((proc.stdout.split('='))[1]).split('\''))
```

`['37.0', 'C\n']`


　前側を取り出します。

```python
print((((proc.stdout.split('='))[1]).split('\''))[0])
```

`37.0`

　文字列を実数に変換します。

```python
print(float((((proc.stdout.split('='))[1]).split('\''))[0]))
```

`37.0`


　プログラムです。

 ```python
 import subprocess

proc = subprocess.check_output('vcgencmd measure_temp',shell=True )
print(proc.decode())

proc = subprocess.run('vcgencmd measure_temp',shell=True, capture_output=True, text=True)
print(proc.stdout)
print(proc.stdout.split('='))
print((proc.stdout.split('='))[1])
print(((proc.stdout.split('='))[1]).split('\''))
print((((proc.stdout.split('='))[1]).split('\''))[0])
print(float((((proc.stdout.split('='))[1]).split('\''))[0]))
```

　別の方法、正規化reライブラリのsub()を併用します。

　'\D'は元の文字列から数字以外を削除（数字を抽出）を使って数字を抽出すると、小数点が文字として捨てられます。

```python
num = re.sub( r'\D', '', proc.stdout)
```

　xx.yという温度が得られるのがわかっていて、xxyという数字が得られるので、実数に変換して10で割ります。

```python
print(float(num)/10.0)
```

　検索して、[小数点を含む数字を得られる記述](https://ja.stackoverflow.com/questions/77797/python-%E3%81%AE%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE%E3%81%A7-%E3%83%89%E3%83%83%E3%83%88-%E3%82%92%E5%90%AB%E3%82%80%E6%95%B0%E5%80%A4%E3%81%AE%E3%81%BF%E3%82%92%E6%8A%BD%E5%87%BA%E3%81%97%E3%81%9F%E3%81%84)がありました。

`[^\d.]`

　勉強不足でこの正規表現を理解できませんが、使ってみます。

```python
num = re.sub( r'[^\d.]', '', proc.stdout)
print(float(num))
```

　どちらの方法も、CPUの温度を得られました。文字列中に数字が1か所しか出てこないという事例です。

　プログラムです。短くなりました。

 ```python
import subprocess
import re

proc = subprocess.run('vcgencmd measure_temp',shell=True, capture_output=True, text=True)

num = re.sub( r'\D', '', proc.stdout)
print(float(num)/10.0)

num = re.sub( r'[^\d.]', '', proc.stdout)
print(float(num))
```

### CPUの温度を4桁7セグメントLED表示器に表示

　上記で得られたCPUの温度を4桁7セグメントLED表示器に表示するプログラムです。

 ```python
 import time
import smbus2
import subprocess
import re

i2c_address=0x71
i2c=smbus2.SMBus(1)

HT16K33_GENERIC_SYSTEM_ON=0x21
HT16K33_GENERIC_DISPLAY_ON=0x81
i2c.write_byte_data(i2c_address,HT16K33_GENERIC_SYSTEM_ON,0)
i2c.write_byte_data(i2c_address,HT16K33_GENERIC_DISPLAY_ON,0)

HT16K33_GENERIC_CMD_BRIGHTNESS=0xe0
i2c.write_byte_data(i2c_address,HT16K33_GENERIC_CMD_BRIGHTNESS,8)

def clearLED():
    i2c.write_i2c_block_data(i2c_address,0,[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])

num={0:0x3f,1:0x06,2:0x5b,3:0x4f,4:0x66,5:0x6d,6:0x7d,7:0x07,8:0x7f,9:0x67} # -;0x40,dot;0x80
seg={1:0,2:2,3:6,4:8}

def dispLED(segment,number,dot):
    if dot:
        i2c.write_byte_data(i2c_address, seg[segment], num[number] +128)  #  |= 0x80
    else:
        i2c.write_byte_data(i2c_address, seg[segment], num[number])

def disp7seg(data):
    if data<0 :
        neg=True
    else:
        neg=False
    dataString=str(data)
    dotNumPlace=dataString.find('.')+1

    dataString=str(abs(data))
    dotNumPlace=dataString.find('.')+1

    segmentPlace=1
    if neg==True:
        i2c.write_byte_data(i2c_address, seg[1], 0x40)
        segmentPlace=2
    lenString= len(dataString)
    mojiichi=1

    while lenString>0:
        dispNum=dataString[mojiichi-1:mojiichi]
        if  dispNum==".":
            mojiichi=mojiichi-1
            segmentPlace=segmentPlace-1
            dispNum=dataString[mojiichi-1:mojiichi]
            dispLED(segmentPlace,int(dispNum),True)
            mojiichi=mojiichi+1
        else:
            dispLED(segmentPlace,int(dispNum),False)
        segmentPlace=segmentPlace+1
        lenString=lenString-1
        mojiichi=mojiichi+1

# main
print("test start")
while 1:
    clearLED()
    proc = subprocess.run('vcgencmd measure_temp',shell=True, capture_output=True, text=True)
    data=float(re.sub( r'[^\d.]', '', proc.stdout))
    print(data)
    disp7seg(data)
    time.sleep(3)
```

:::note warn
　このあと、ラズパイが立ち上がったら、このプログラムが自動で実行できるようにするという設定にチャレンジしましたが、実現できていません。bookwormに代わって、systemdの記述が変わったという解説は見つかっていませんが。
:::