<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>python &#8211; richliu&#039;s blog</title>
	<atom:link href="https://blog.richliu.com/tag/python/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.richliu.com</link>
	<description>Linux, 工作, 生活, 家人</description>
	<lastBuildDate>Sun, 12 May 2024 08:56:00 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.6.2</generator>
	<item>
		<title>Python mysql.connector.errors.DataError: 1366 (22007): Incorrect string value:</title>
		<link>https://blog.richliu.com/2024/05/12/5973/python-mysql-connector-errors-dataerror-1366-22007-incorrect-string-value/</link>
					<comments>https://blog.richliu.com/2024/05/12/5973/python-mysql-connector-errors-dataerror-1366-22007-incorrect-string-value/#respond</comments>
		
		<dc:creator><![CDATA[richliu]]></dc:creator>
		<pubDate>Sun, 12 May 2024 08:55:58 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[MariaDB]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[UTF-8]]></category>
		<guid isPermaLink="false">https://blog.richliu.com/?p=5973</guid>

					<description><![CDATA[<p>After check all mysql (mariadb) setting, I realize that [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.richliu.com/2024/05/12/5973/python-mysql-connector-errors-dataerror-1366-22007-incorrect-string-value/">Python mysql.connector.errors.DataError: 1366 (22007): Incorrect string value:</a> appeared first on <a rel="nofollow" href="https://blog.richliu.com">richliu&#039;s blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>After check all mysql (mariadb) setting, I realize that should be client issue, it needs to add &#8220;chatset=&#8217;utf8mb4&#8242;&#8221; to mysql.connector.connect command. </p>



<pre class="wp-block-preformatted">mydb = mysql.connector.connect(
    host="IP or Host",
    user="&lt;user>",
    passwd="&lt;password>",
    database="&lt;yourDB>",
    # set charset to utf8mb4 to support emojis
    charset='utf8mb4'
)</pre>



<p>ref. https://stackoverflow.com/a/73648817/1371373</p>



<p></p>
<p>The post <a rel="nofollow" href="https://blog.richliu.com/2024/05/12/5973/python-mysql-connector-errors-dataerror-1366-22007-incorrect-string-value/">Python mysql.connector.errors.DataError: 1366 (22007): Incorrect string value:</a> appeared first on <a rel="nofollow" href="https://blog.richliu.com">richliu&#039;s blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.richliu.com/2024/05/12/5973/python-mysql-connector-errors-dataerror-1366-22007-incorrect-string-value/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Raspberry Pi Pico W + PicoOLED 2.23 + Arduino 顯示天氣預報降雨機率和空污指數</title>
		<link>https://blog.richliu.com/2023/01/15/5079/raspberry-pi-pico-w-picooled-2-23-arduino-%e9%a1%af%e7%a4%ba%e5%a4%a9%e6%b0%a3%e9%a0%90%e5%a0%b1%e9%99%8d%e9%9b%a8%e6%a9%9f%e7%8e%87%e5%92%8c%e7%a9%ba%e6%b1%a1%e6%8c%87%e6%95%b8/</link>
					<comments>https://blog.richliu.com/2023/01/15/5079/raspberry-pi-pico-w-picooled-2-23-arduino-%e9%a1%af%e7%a4%ba%e5%a4%a9%e6%b0%a3%e9%a0%90%e5%a0%b1%e9%99%8d%e9%9b%a8%e6%a9%9f%e7%8e%87%e5%92%8c%e7%a9%ba%e6%b1%a1%e6%8c%87%e6%95%b8/#respond</comments>
		
		<dc:creator><![CDATA[richliu]]></dc:creator>
		<pubDate>Sun, 15 Jan 2023 10:12:54 +0000</pubDate>
				<category><![CDATA[Computer/Technical]]></category>
		<category><![CDATA[ARM]]></category>
		<category><![CDATA[Embedded]]></category>
		<category><![CDATA[Hardware]]></category>
		<category><![CDATA[Arduino]]></category>
		<category><![CDATA[Json]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[Raspberry Pi Pico]]></category>
		<guid isPermaLink="false">https://blog.richliu.com/?p=5079</guid>

					<description><![CDATA[<p>有時候人生就是不能亂買東西，一步錯步步錯，然後就弄了這個出來，當然不是圖中大螢幕的屋內屋外溫濕度狀況，而是左上 [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.richliu.com/2023/01/15/5079/raspberry-pi-pico-w-picooled-2-23-arduino-%e9%a1%af%e7%a4%ba%e5%a4%a9%e6%b0%a3%e9%a0%90%e5%a0%b1%e9%99%8d%e9%9b%a8%e6%a9%9f%e7%8e%87%e5%92%8c%e7%a9%ba%e6%b1%a1%e6%8c%87%e6%95%b8/">Raspberry Pi Pico W + PicoOLED 2.23 + Arduino 顯示天氣預報降雨機率和空污指數</a> appeared first on <a rel="nofollow" href="https://blog.richliu.com">richliu&#039;s blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<div class="wp-block-image">
<figure class="alignright size-full is-resized"><img fetchpriority="high" decoding="async" src="https://blog.richliu.com/wp-content/uploads/2023/01/image.png" alt="" class="wp-image-5080" width="360" height="269" srcset="https://blog.richliu.com/wp-content/uploads/2023/01/image.png 1460w, https://blog.richliu.com/wp-content/uploads/2023/01/image-600x450.png 600w, https://blog.richliu.com/wp-content/uploads/2023/01/image-768x575.png 768w" sizes="(max-width: 360px) 100vw, 360px" /></figure></div>


<p>有時候人生就是不能亂買東西，一步錯步步錯，然後就弄了這個出來，當然不是圖中大螢幕的屋內屋外溫濕度狀況，而是左上角小小的溫度預測<br /><br />至於怎麼來的，一切都要從邪惡的阿媽爽60元免運說起，因為60元免運，有時候就會將有些小東西放到購物車內，因為有時候即使加了稅金，從美亞（美國亞馬遜Amazon）網站買東西還比淘寶買便宜，更不要說很多東西只有美亞有，這時候小東西湊60元免運頗方便的<br /><br />原來是我有二張 Arduino 的板子，本來也只是接來做溫度偵測，也沒有什麼用，想說接個小螢幕顯示一下天氣預報，但是這東西又不是很必要，就想想而已，就隨便找了一個看起來順眼的 SPI LCD 和 OLED （想說比較省電）就放到購物車了，上個月美國很多東西都特價，兩雙鞋子才 30 元美金，這塊 OLED 好像也才 15 上下，就被拿來湊運費了，沒想到我手上並沒有東西可以接</p>



<span id="more-5079"></span>



<h2 class="wp-block-heading">Waveshare 2.23 inch OLED</h2>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-full"><img decoding="async" width="609" height="293" data-id="5081" src="https://blog.richliu.com/wp-content/uploads/2023/01/image-1.png" alt="" class="wp-image-5081" srcset="https://blog.richliu.com/wp-content/uploads/2023/01/image-1.png 609w, https://blog.richliu.com/wp-content/uploads/2023/01/image-1-600x289.png 600w" sizes="(max-width: 609px) 100vw, 609px" /></figure>



<figure class="wp-block-image size-full"><img decoding="async" width="609" height="312" data-id="5082" src="https://blog.richliu.com/wp-content/uploads/2023/01/image-2.png" alt="" class="wp-image-5082" srcset="https://blog.richliu.com/wp-content/uploads/2023/01/image-2.png 609w, https://blog.richliu.com/wp-content/uploads/2023/01/image-2-600x307.png 600w" sizes="(max-width: 609px) 100vw, 609px" /></figure>
</figure>



<p>這片是 <a href="https://www.amazon.com/Waveshare-2-23inch-Raspberry-Interface-Operating/dp/B094K2G8K5?th=1" target="_blank" rel="noreferrer noopener">Waveshare Pico OLED 2.23</a> 是一片 2.23 吋的 OLED 螢幕，內建 SSD1305 driver ，可以用 SPI/I2C bus 驅動<br />最大的優勢是，他可以和 Raspberry Pi Pico 的接頭整合在一起</p>



<p>不過我買來之後就傻眼了，因為我以為只是 SPI 螢幕，但是沒有 Raspberry Pi Pico 啊～（謎之音，藉口，明明可以外接）所以本來想接 Arduino 的，只好就買了一片 Raspberry Pi Pico W ，Raspberry Pi Pico W 是有 WiFi 的版本，我想說都要買了，買有 WiFi 的比較方便<br /><br />如果有去 Amazon 網站上會有一行字提到，事後來看可能是地雷<br />The built-in controller used in this OLED is SSD1305, <strong>which has 132 × 64 bit SRAM, supports a maximum 132 × 64 pixels screen, supports SPI/I2C/8bit 8080 parallel port. The solution of this screen is 128 × 32 pixels, so the internal SRAM is not fully used</strong>. This module uses four-wire SPI and I2C interfaces, with good compatibility and high transmission speed.<br /><br />至少以目前看到的資料，只有他的 demo code 可以用，其他沒找到有人成功使它完全正常工作的範例</p>



<h2 class="wp-block-heading">系統架構</h2>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://blog.richliu.com/wp-content/uploads/2023/01/image-3.png" alt="" class="wp-image-5083" width="633" height="327" srcset="https://blog.richliu.com/wp-content/uploads/2023/01/image-3.png 1317w, https://blog.richliu.com/wp-content/uploads/2023/01/image-3-600x310.png 600w, https://blog.richliu.com/wp-content/uploads/2023/01/image-3-768x397.png 768w" sizes="(max-width: 633px) 100vw, 633px" /></figure>



<p>架構如上，不過為什麼要多一個中介 Server 呢？因為在 PC 上改 code 還是簡單速度快，Arduino 的開發環境很怪， compile 很慢，而整個開發驗證流程太長，我也沒要商業化，當然是選自己好用的為主<br />中間互丟就用 udp 就好，簡單速度快還沒有什麼多有的沒有的事情，畢竟一組 packet 也不會超過 1K</p>



<h2 class="wp-block-heading">Raspberry Pi Pico W</h2>



<p><a href="https://shop.playrobot.com/products/raspberry-pi-pico-w" target="_blank" rel="noreferrer noopener">Raspberry Pi Pico W</a> 是 RP2040 (ARM Cortex M0+ 雙核處理器) 的 CPU + Infineon CYW43439 WiFi 和藍牙，其他就看看規格吧，Raspberry Pi Pico 預設的開發環境是 <a href="https://micropython.org/download/rp2-pico-w/" target="_blank" rel="noreferrer noopener">MicroPython</a> ，用的是 <a href="https://thonny.org/" target="_blank" rel="noreferrer noopener">Thonny </a>這個 IDE<br />另外一個就是使用 <a href="https://www.arduino.cc/en/software" target="_blank" rel="noreferrer noopener">Arduino</a> 加上 <a href="https://github.com/earlephilhower/arduino-pico" target="_blank" rel="noreferrer noopener">arduino-pico</a> 套件<br />我最後是選了 Arduino + Pico SDK 套件，好吧，我也忘了當初是因為什麼會用 Arduino 這個組合的，大概是 Arduino 之前寫過，比較熟悉吧</p>



<p>對了，在跑 Arduino raspberry Pi pico 的 sample code 時，不要選 Fade 或是點 LED 這種網路上常見的 sample code ，因為 Raspberry Pi pico 的 LED 是放在 WiFi 那邊，不是 GPIO 直出，所以只是要驗證可不可以用，example code 請選 teampterature 就好</p>



<h2 class="wp-block-heading">Arduino </h2>



<p>其實 Arduino 的使用還算方便，但是我想到的組合會踏到一個一般人的地雷，ArduinoJson 要使用 C++，但是因為不是用到很複雜的功能，所以抄一抄還可以<br /><br />Arduino 要設定 Additional Boards Manager URLs ，請按照<a href="https://github.com/earlephilhower/arduino-pico" target="_blank" rel="noreferrer noopener">arduino-pico</a>  的說明文件，加上 <a href="https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json" target="_blank" rel="noopener">https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json</a></p>



<p>在安裝的過程中，Windows 所有的 driver 都請同意安裝，否則可能會有奇怪的問題</p>



<p>Tool -&gt; manager Libraries 請安裝 ArduinoJson 和 U8g2 Library</p>



<h2 class="wp-block-heading">Python Server </h2>



<p>抓取資料的部份主要是參考之前的作品<a href="https://blog.richliu.com/2019/10/17/4192/python-%E5%8F%96%E5%BE%97-pm2-5-%E5%92%8C%E5%A4%A9%E6%B0%A3%E8%B3%87%E8%A8%8A/" target="_blank" rel="noreferrer noopener"> Python 取得 PM2.5 和天氣資訊</a>，不過都過了這麼久了，有些部份不一樣，例如文內的 PM2.5 就變 pm2.5</p>



<p>預測天氣部份就使用氣象局的資料，氣象局有針對各縣市鄉鎮的未來二天預報資料，找到你自己要的鄉鎮，再取出資料即可，以新北市來說是 F-D0047-069</p>



<h3 class="wp-block-heading">天氣預測資料</h3>



<p>以下是抓出未來 18 小時共六筆的溫度預測和未來 18 小時三筆的降雨預測資料</p>



<pre class="wp-block-preformatted"> res = "https://opendata.cwb.gov.tw/fileapi/v1/opendataapi/F-D0047-069?Authorization=[請填入你的KEY]D&amp;format=JSON"

        while True:
            try:
                with urllib.request.urlopen(res) as url:
                    data = url.read()
            except urllib.error.URLError as e:
                self.LOG.error(e)
                return -1
            try:
                my_object = json.loads(data.decode('utf-8'))
            except:
                self.LOG.error("Json Error")
                return -1

            item = my_object['cwbopendata']['dataset']['locations']['location']

            for i in range(len(item)):
                if item[i]['locationName'] == "鶯歌區":
                    for j in range(len(item[i]['weatherElement'])):
                        if item[i]['weatherElement'][j]['elementName'] == "T":
                            weather_time_value = item[i]['weatherElement'][j]['time']
                            # 抓出每一個時間和溫度
                            for k in range(len(weather_time_value)):
                                weather_date = weather_time_value[k]['dataTime']
                                data_time = datetime.strptime(weather_date, '%Y-%m-%dT%H:%M:%S%z')
                                clock_string = data_time.strftime('%H')
                                tw_weather.w_data["temp"][clock_string] = weather_time_value[k]['elementValue']['value']
                                self.LOG.debug("now is %s temp is %s" % (clock_string, weather_time_value[k]['elementValue']['value']))
                                # 每三小時一筆，取 18 小時的數據
                                if k >= 5:
                                    break
                        # PoP6h 六小時降雨機率
                        if item[i]['weatherElement'][j]['elementName'] == "PoP6h":
                            weather_rain_value = item[i]['weatherElement'][j]['time']
                            # 抓出每一個時間和溫度
                            for k in range(len(weather_rain_value)):
                                weather_date = weather_rain_value[k]['startTime']
                                data_time = datetime.strptime(weather_date, '%Y-%m-%dT%H:%M:%S%z')
                                clock_string = data_time.strftime('%H')
                                tw_weather.w_data["rain"][clock_string] = weather_rain_value[k]['elementValue']['value']
                                self.LOG.debug("now is %s rain is %s" % (clock_string, weather_rain_value[k]['elementValue']['value']))
                                # 每六小時一筆，取 24 小時的數據
                                if k >= 3:
                                    break</pre>



<h3 class="wp-block-heading">UDP Server</h3>



<p>UDP server 就很簡單，收到資料就將 json 資料丟出去就好，因為資料量少應該不會出問題吧<br /></p>



<pre class="wp-block-preformatted">    def udp_server(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.bind(("0.0.0.0", 9999))

        self.LOG.info("Server IP address: %s", socket.gethostbyname(socket.gethostname()))

        while True:
            data, addr = sock.recvfrom(1024)

            json_send_data = json.dumps(self.serve_data)
            sock.sendto(json_send_data.encode(), addr)
</pre>



<h2 class="wp-block-heading">Arduino Sample Code </h2>



<p>Arduino 其實對開發者很友善，安裝 Pico W 套件的時候內有大量的 Sample code ，WiFi 部份就照抄 Sample code 就可以了，這部份不是很大的問題　</p>



<h3 class="wp-block-heading">UDP Client </h3>



<p>不知道大家是不是都不寫 UDP Client ，網路上大部份的範例都是拿 Arduino 當 server 用，而且 WiFiUdp 和 EthernetUDP 也有一點差別，我自己的做法如下<br />Udp.beginPacket 就可以直接送 packet 出去，送出去之後等待二秒收資料就好，不是很好的做法但是我人懶，不想弄異步傳輸，可以用就好</p>



<pre class="wp-block-preformatted">const char* serverip = "10.0.0.1";
const uint16_t serverport = 9999;
const uint16_t localport = 9999;

void setup(void) {
    Udp.begin(localport);
}

void loop(void){
  Udp.beginPacket(serverip, serverport);
  Udp.write("Hello");
  Udp.endPacket();

  delay(2000);

  int packetSize = Udp.parsePacket();
  if (packetSize){
    Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    packetBuffer[packetSize] = 0;

    // The packet is coming from the remote server
    Serial.println("Received packet from: ");
    Serial.println(Udp.remoteIP());
    Serial.println("Packet is: ");
    Serial.println(packetBuffer);
}</pre>



<h2 class="wp-block-heading">ArduinoJson Sample Code</h2>



<p>說實在這個用的時候不知道取出 Json 的資料要會一點 C++ ，雖然我也已經不太懂 C++，不過這東西沒有很難，照抄就好，當初會不會不用 Json 比較好？我不知道，不過用用看嘛，我是記得看到已經到很多版了，應該頗多人用，這樣就不用太害怕要自己修 code <br /><br />但是開發過程中，在這邊碰到當機的問題找了好久，才知道 Arduino 如果程式寫到會當掉，那就要使用 Bootsel 更新，要不然就會一直卡在當機那邊，要不然一直以為是 host 的 driver 爛了<br /><br />以下是 Sample code </p>



<pre class="wp-block-preformatted">// 網路上的範例 200 太小，以我大概 150 byte 還是要設大一點，要不然也有 DynamicJsonDocument 可以用
StaticJsonDocument&lt;500&gt; doc;

    // decode json format 
    DeserializationError error = deserializeJson(doc, packetBuffer);
    if (error) {
        Serial.println("Deserialization failed: " + String(error.c_str()));
        return;
    }
    JsonObject temp = doc["temp"];

    sprintf(buffer,"TEMP: ");
    for (JsonPair kv : temp) {
      sprintf(buffer + strlen(buffer), "%s:%s ", kv.key().c_str(), kv.value().as&lt;const char*&gt;());
      count++;
      if(count &gt; 2){
        Serial.println(buffer);
        oled_show_generalmsg(5,y,buffer,0);

        sprintf(buffer,"TEMP: ");
        y = y+ 8;
        count = 0;
      }
    }
    // Raining chance
    temp = doc["rain"];
    sprintf(buffer,"R: ");
    count = 0; 
    for (JsonPair kv : temp) {
      sprintf(buffer + strlen(buffer), "%s:%s%% ", kv.key().c_str(), kv.value().as&lt;const char*&gt;());
      count++;
      // only show 3 records here 
      if (count &gt; 2)
        break; 
    }
    Serial.println(buffer);
    oled_show_generalmsg(5,y,buffer,0);
    y=y+8;

    int pm25 = atoi(doc["pm2.5"]);
    int pm10 = atoi(doc["pm10"]);

    const char *level; 
    if ( pm25 &lt;15 || pm10 &lt; 50 ){
      level = "Good"; 
    } else if ( (pm25 &gt;= 15 &amp;&amp; pm25 &lt;35) || (pm10 &gt;= 50 &amp;&amp; pm10 &lt; 100)){
      level = "Medium";
    } else if ( (pm25 &gt;= 35 &amp;&amp; pm25 &lt;54) || (pm10 &gt;= 100 &amp;&amp; pm10 &lt; 254)){
      level = "Bad";
    }else{
      level = "SBad";
    }
    
    sprintf(buffer , "PM2.5:%d PM10:%d Lv:%s", pm25, pm10, level);
    Serial.println(buffer);
    oled_show_generalmsg(5,y,buffer,0);</pre>



<h2 class="wp-block-heading">u8g2 display Library</h2>



<p>這個是 Waveshare Pico OLED 2.23 唯一可以用的 Library ，可能其他 Library 也可以用，但是我沒找到<br />我試過一些 ssd1305 和 ssd1306 的 library ，像 Adafruit ssd1306 SPI 就可以驅動，可以顯示，但是沒辦法正確顯示<br /><br />u8g2 只可以顯示，但是在邊界的地方會出問題（請見本文第一張圖最右邊的白色部份），本人並沒有要做產品不想幫廠商 debug 這種事，小小小缺點就眼不見為淨就好<br /><br />放個 sample code 就好了<br />u8g2 可以選字體還不錯，也有人教如何顯示<a href="https://atceiling.blogspot.com/2020/12/arduino103-u8g2.html" target="_blank" rel="noreferrer noopener">中文</a>，不過我沒用到中文就不想試了，對了128&#215;32真是太小了，顯示好擠，還是要買大一點的好，最好是 320&#215;240 <s>還要有觸控</s></p>



<p>oled_show_generalmsg 是我拿來秀字體用的，但是因為要避開這塊面版的問題，都要 offset 5 pixels （應該有其他解決方案，但是大部份正常我就懶得試了）<br />顯示字串的部份上面那一塊有 sample code ，下面就不放了</p>



<pre class="wp-block-preformatted">U8G2_SSD1305_128X32_NONAME_F_4W_SW_SPI  u8g2(U8G2_R0, /* clock=*/ 10, /* data=*/ 11, /* cs=*/ 9, /* dc=*/ 8, /* reset=*/ 12);

void oled_show_generalmsg(int x,int y, const char *msg, int clearbuffer=1){
    if (clearbuffer == 1)
        u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_5x8_tr );
    
    u8g2.drawStr(x,y,msg);
    u8g2.sendBuffer();
}

void setup(void) {
  pinMode(9, OUTPUT);
  digitalWrite(9, 0);	// default output in I2C mode for the SSD1306 test shield: set the i2c adr to 0

  u8g2.begin();
}</pre>



<h2 class="wp-block-heading">Python Server on Docker</h2>



<p>最後當然要將 python server 放到 docker 上面去，以下是幾個步驟</p>



<p>產生 Dockerfile </p>



<pre class="wp-block-preformatted"># Use an official Python runtime as the base image
FROM python:3.9

# Set the working directory
WORKDIR /app

# Copy the requirements file
COPY requirements.txt .

# Install the required libraries
RUN /usr/local/bin/python -m pip install --upgrade pip
RUN pip install --no-cache-dir -r requirements.txt

# Copy the Python script
COPY weather.py .

# Run the script
CMD ["python", "weather.py"]
</pre>



<p>產生 requirement.txt</p>



<pre class="wp-block-preformatted">urllib3
jsonschema
</pre>



<p>產生 docker image，這個如果程式有改動就要再執行一次</p>



<p>docker build -f Dockerfile -t weatherdaemon .</p>



<p>執行 docker ，udp 的 portforwarding 和 tcp 稍稍不一樣，加上 timezome 讓 script debug 顯示的時間更正確</p>



<pre class="wp-block-preformatted">docker run -v /usr/share/zoneinfo/Asia/Taipei:/etc/localtime -p 8888:8888/udp weatherdaemon
# Daemon mode
# docker run -d -v /usr/share/zoneinfo/Asia/Taipei:/etc/localtime -p 8888:8888/udp weatherdaemon</pre>



<h2 class="wp-block-heading">功耗</h2>



<p>大功告成，組合測試，都是 embedded system 一定要測一下功耗的啊<br />大略都在 0.54W 左右，算還可以吧</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="2560" height="1728" src="https://blog.richliu.com/wp-content/uploads/2023/01/IMG_20230115_015554-scaled.jpg" alt="" class="wp-image-5086" srcset="https://blog.richliu.com/wp-content/uploads/2023/01/IMG_20230115_015554-scaled.jpg 2560w, https://blog.richliu.com/wp-content/uploads/2023/01/IMG_20230115_015554-600x405.jpg 600w, https://blog.richliu.com/wp-content/uploads/2023/01/IMG_20230115_015554-768x518.jpg 768w, https://blog.richliu.com/wp-content/uploads/2023/01/IMG_20230115_015554-1536x1037.jpg 1536w, https://blog.richliu.com/wp-content/uploads/2023/01/IMG_20230115_015554-2048x1382.jpg 2048w" sizes="(max-width: 2560px) 100vw, 2560px" /></figure>



<p><br />當然一定要拿一顆 186550 來當行動電源的，這樣就可以到處放了<br />約略可以顯示 16 小時，算可以了吧，這個耗電量應該還是要插電比較好</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="2560" height="1728" src="https://blog.richliu.com/wp-content/uploads/2023/01/IMG_20230115_091630-scaled.jpg" alt="" class="wp-image-5087" srcset="https://blog.richliu.com/wp-content/uploads/2023/01/IMG_20230115_091630-scaled.jpg 2560w, https://blog.richliu.com/wp-content/uploads/2023/01/IMG_20230115_091630-600x405.jpg 600w, https://blog.richliu.com/wp-content/uploads/2023/01/IMG_20230115_091630-768x518.jpg 768w, https://blog.richliu.com/wp-content/uploads/2023/01/IMG_20230115_091630-1536x1037.jpg 1536w, https://blog.richliu.com/wp-content/uploads/2023/01/IMG_20230115_091630-2048x1382.jpg 2048w" sizes="(max-width: 2560px) 100vw, 2560px" /></figure>



<h2 class="wp-block-heading">ChatGPT</h2>



<p>為什麼會有這個，應該不是很意外吧？<br />這次因為都不是很熟悉的東西，所以很多事情都問 ChatGPT 拿答案<br /><br />簡單的心得是，比 Google 好用，但是問題很多<br /><br />原因是因為 Google 會給很多文章，但是這些文章不見得是你要的，或是寫很長一串重點找半天</p>



<p>ChatGPT 總是可以直擊問題給出答案，然後有些問題會很容易翻車，像是</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1114" height="759" src="https://blog.richliu.com/wp-content/uploads/2023/01/image-4.png" alt="" class="wp-image-5088" srcset="https://blog.richliu.com/wp-content/uploads/2023/01/image-4.png 1114w, https://blog.richliu.com/wp-content/uploads/2023/01/image-4-600x409.png 600w, https://blog.richliu.com/wp-content/uploads/2023/01/image-4-768x523.png 768w" sizes="(max-width: 1114px) 100vw, 1114px" /><figcaption>無法分辨那個才是 package</figcaption></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1003" height="787" src="https://blog.richliu.com/wp-content/uploads/2023/01/image-5.png" alt="" class="wp-image-5089" srcset="https://blog.richliu.com/wp-content/uploads/2023/01/image-5.png 1003w, https://blog.richliu.com/wp-content/uploads/2023/01/image-5-600x471.png 600w, https://blog.richliu.com/wp-content/uploads/2023/01/image-5-768x603.png 768w" sizes="(max-width: 1003px) 100vw, 1003px" /><figcaption>給了錯的參數</figcaption></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1210" height="701" src="https://blog.richliu.com/wp-content/uploads/2023/01/image-6.png" alt="" class="wp-image-5090" srcset="https://blog.richliu.com/wp-content/uploads/2023/01/image-6.png 1210w, https://blog.richliu.com/wp-content/uploads/2023/01/image-6-600x348.png 600w, https://blog.richliu.com/wp-content/uploads/2023/01/image-6-768x445.png 768w" sizes="(max-width: 1210px) 100vw, 1210px" /><figcaption>但是還是可以糾正回來</figcaption></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="971" height="654" src="https://blog.richliu.com/wp-content/uploads/2023/01/image-7.png" alt="" class="wp-image-5091" srcset="https://blog.richliu.com/wp-content/uploads/2023/01/image-7.png 971w, https://blog.richliu.com/wp-content/uploads/2023/01/image-7-600x404.png 600w, https://blog.richliu.com/wp-content/uploads/2023/01/image-7-768x517.png 768w" sizes="(max-width: 971px) 100vw, 971px" /><figcaption>那個 as&lt;char *&gt;()) 是錯的，要改用 as&lt;const char *&gt;()) 才對</figcaption></figure>



<p>如果是初學者，又沒有排除故障能力，那麼直接用 chatgpt 就會翻車，不過如果是已經懂得怎麼排除問題，又有一定基礎，使用 chatgpt 可以加速很多開發時的工作</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1162" height="819" src="https://blog.richliu.com/wp-content/uploads/2023/01/image-8.png" alt="" class="wp-image-5092" srcset="https://blog.richliu.com/wp-content/uploads/2023/01/image-8.png 1162w, https://blog.richliu.com/wp-content/uploads/2023/01/image-8-600x423.png 600w, https://blog.richliu.com/wp-content/uploads/2023/01/image-8-768x541.png 768w" sizes="(max-width: 1162px) 100vw, 1162px" /><figcaption>幫忙修改程式碼，加上忽略的部份</figcaption></figure>



<p>總之，這東西如果價格不貴，我會付費使用，而且是常駐在系統上，它能大幅增進我的能力，尤其是現在少寫 code 了，很多東西都忘得差不多了</p>
<p>The post <a rel="nofollow" href="https://blog.richliu.com/2023/01/15/5079/raspberry-pi-pico-w-picooled-2-23-arduino-%e9%a1%af%e7%a4%ba%e5%a4%a9%e6%b0%a3%e9%a0%90%e5%a0%b1%e9%99%8d%e9%9b%a8%e6%a9%9f%e7%8e%87%e5%92%8c%e7%a9%ba%e6%b1%a1%e6%8c%87%e6%95%b8/">Raspberry Pi Pico W + PicoOLED 2.23 + Arduino 顯示天氣預報降雨機率和空污指數</a> appeared first on <a rel="nofollow" href="https://blog.richliu.com">richliu&#039;s blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.richliu.com/2023/01/15/5079/raspberry-pi-pico-w-picooled-2-23-arduino-%e9%a1%af%e7%a4%ba%e5%a4%a9%e6%b0%a3%e9%a0%90%e5%a0%b1%e9%99%8d%e9%9b%a8%e6%a9%9f%e7%8e%87%e5%92%8c%e7%a9%ba%e6%b1%a1%e6%8c%87%e6%95%b8/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Python 取得 PM2.5 和天氣資訊</title>
		<link>https://blog.richliu.com/2019/10/17/4192/python-%e5%8f%96%e5%be%97-pm2-5-%e5%92%8c%e5%a4%a9%e6%b0%a3%e8%b3%87%e8%a8%8a/</link>
					<comments>https://blog.richliu.com/2019/10/17/4192/python-%e5%8f%96%e5%be%97-pm2-5-%e5%92%8c%e5%a4%a9%e6%b0%a3%e8%b3%87%e8%a8%8a/#comments</comments>
		
		<dc:creator><![CDATA[richliu]]></dc:creator>
		<pubDate>Thu, 17 Oct 2019 15:16:41 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">https://blog.richliu.com/?p=4192</guid>

					<description><![CDATA[<p>最近終於將很久之前就說要架的室內 PM 2.5 偵測弄起來，上一版是用 Cacti 做的，但是有點過時了，這一 [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.richliu.com/2019/10/17/4192/python-%e5%8f%96%e5%be%97-pm2-5-%e5%92%8c%e5%a4%a9%e6%b0%a3%e8%b3%87%e8%a8%8a/">Python 取得 PM2.5 和天氣資訊</a> appeared first on <a rel="nofollow" href="https://blog.richliu.com">richliu&#039;s blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image"><figure class="alignright is-resized"><img loading="lazy" decoding="async" src="https://blog.richliu.com/wp-content/uploads/2019/10/image-1024x702.png" alt="" class="wp-image-4193" width="240" height="164" srcset="https://blog.richliu.com/wp-content/uploads/2019/10/image-1024x702.png 1024w, https://blog.richliu.com/wp-content/uploads/2019/10/image-300x206.png 300w, https://blog.richliu.com/wp-content/uploads/2019/10/image-768x526.png 768w, https://blog.richliu.com/wp-content/uploads/2019/10/image.png 1509w" sizes="(max-width: 240px) 100vw, 240px" /></figure></div>



<p>最近終於將很久之前就說要架的室內 PM 2.5 偵測弄起來，上一版是用 Cacti 做的，但是有點過時了，這一版是用 Grafana + Prometheus 做的，看起來就漂亮多了<br /><br />不過架上去之後的問題是，想比較數值，但是又不想再組一套系統出來，畢竟感測器也是成本，不如就用現成的氣象和環保局的數據吧，反正都只是參考用的，看個大概就好了<br /></p>



<span id="more-4192"></span>



<h4 class="wp-block-heading">PM 2.5 的數據</h4>



<p>這是取用 <a rel="noreferrer noopener" aria-label="PM 2.5 Open Data  (opens in a new tab)" href="https://pm25.lass-net.org/" target="_blank">PM 2.5 Open Data </a>網站的數據，看起來是中研院架的，但是不知道為什麼是在 .org 下，不過沒關係，其中有提供很多來源，我自己是取用環保局的資料<br /><br />環保局的資料有一個問題，並不是每個地方都有，所以我是選用土城的測站，因為離家最近<br /><br />Open Data 的資料是 .gz ，不需要認證，所以用 urlopen 下載下來送到 gzip module 最後給 json 就可以解了，程式如下<br /><br />這個數據是每 10 分鐘更新一次，所以每 10 分鐘抓一次即可</p>



<pre class="wp-block-preformatted">def getpm25():
     req = Request(PM25URL)
     req.add_header('Accept-Encoding','gzip')
     response = urlopen(req)
     content = gzip.decompress(response.read())
     my_object = json.loads(content.decode('utf-8'))
     item = my_object['feeds'] 
     for i in range(len(item)):     
         # print(item[i]['County'])     
         if item[i]['SiteName'] == "土城":         
            print(item[i])         
            print("PM25:", item[i]['PM2_5'])         
            print("PM10:", item[i]['PM10'])</pre>



<h4 class="wp-block-heading">天氣的數據</h4>



<p>天氣的數據是取用中央氣象局的，目前 Google 到的資料也略有出入，所以我就寫個簡單的 Code 解出我要的資訊，應該可以更漂亮的解法，不過寫個 Sample 省大家時間也不錯<br /><br />氣象局的資料要去氣象資料開放平台註冊，註冊完會給一組 API ，再利用這組 API Key 抓你要的資料，我這邊選用的是 JSON 格式<br />O-A0001-001 ：資料型態，我這是即時氣象資料<br />Authorization=CWB-111111E2-1877-4711-2624-216276053413: API Key ，後面 KEY 要換成自己申請的<br />format=JSON，資料格式，還有其他的，但是我只有試 JSON<br /><br />if localitem[j][&#8216;elementName&#8217;] == &#8220;TEMP&#8221;:　>  氣溫<br />elif localitem[j][&#8216;elementName&#8217;] == &#8220;HUMD&#8221;: > 濕度<br /><br />說明文件可以參考 <a rel="noreferrer noopener" aria-label="中央氣象局開放資料平臺之資料擷取API (opens in a new tab)" href="https://opendata.cwb.gov.tw/dist/opendata-swagger.html" target="_blank">中央氣象局開放資料平臺之資料擷取API</a> ，有比較詳細的說明<br /></p>



<pre class="wp-block-preformatted">def get_local_temperature():
     res = "https://opendata.cwb.gov.tw/fileapi/v1/opendataapi/O-A0001-001?Authorization=CWB-111111E2-1877-4711-2624-216276053413&amp;format=JSON"
     with urllib.request.urlopen(res) as url:
         data = url.read()
         my_object = json.loads(data.decode('utf-8'))
         item = my_object['cwbopendata']['location']
         # print(item)
         for i in range(len(item)):
             # print(item[i])
             if item[i]['locationName'] == "鶯歌":
                 # print(item[i])             
                 # print(item[i]['weatherElement'])             
                 localitem = item[i]['weatherElement']             
                 for j in range(len(localitem)):                 
                     # print(localitem[j])                 
                     if localitem[j]['elementName'] == "TEMP":
                         print("Temp:", localitem[j]['elementValue']['value'])                 
                     elif localitem[j]['elementName'] == "HUMD":
                         print("RH:", localitem[j]['elementValue']['value'])</pre>



<p></p>
<p>The post <a rel="nofollow" href="https://blog.richliu.com/2019/10/17/4192/python-%e5%8f%96%e5%be%97-pm2-5-%e5%92%8c%e5%a4%a9%e6%b0%a3%e8%b3%87%e8%a8%8a/">Python 取得 PM2.5 和天氣資訊</a> appeared first on <a rel="nofollow" href="https://blog.richliu.com">richliu&#039;s blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.richliu.com/2019/10/17/4192/python-%e5%8f%96%e5%be%97-pm2-5-%e5%92%8c%e5%a4%a9%e6%b0%a3%e8%b3%87%e8%a8%8a/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>PyCharm 內執行 QT Designer 和 ui 轉 py</title>
		<link>https://blog.richliu.com/2019/02/21/3879/pycharm-%e5%85%a7%e5%9f%b7%e8%a1%8c-qt-designer-%e5%92%8c-ui-%e8%bd%89-py/</link>
					<comments>https://blog.richliu.com/2019/02/21/3879/pycharm-%e5%85%a7%e5%9f%b7%e8%a1%8c-qt-designer-%e5%92%8c-ui-%e8%bd%89-py/#comments</comments>
		
		<dc:creator><![CDATA[richliu]]></dc:creator>
		<pubDate>Thu, 21 Feb 2019 15:10:11 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[PyCharm]]></category>
		<category><![CDATA[PyQT]]></category>
		<category><![CDATA[PyQT5]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[QT]]></category>
		<category><![CDATA[QT Creator]]></category>
		<guid isPermaLink="false">https://blog.richliu.com/?p=3879</guid>

					<description><![CDATA[<p>看了幾篇文章都有些疏漏，並沒有辦法真正的做到直接在程式內直接呼叫 External tool 做到這兩件事 都 [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.richliu.com/2019/02/21/3879/pycharm-%e5%85%a7%e5%9f%b7%e8%a1%8c-qt-designer-%e5%92%8c-ui-%e8%bd%89-py/">PyCharm 內執行 QT Designer 和 ui 轉 py</a> appeared first on <a rel="nofollow" href="https://blog.richliu.com">richliu&#039;s blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>看了幾篇文章都有些疏漏，並沒有辦法真正的做到直接在程式內直接呼叫 External tool 做到這兩件事<br /><br />都會有一些錯誤訊息</p>



<span id="more-3879"></span>



<p>我的環境是 Ubuntu 18.04 ，用 snap 安裝的 PyCharm <br />順便安裝 QT 相關的環境</p>



<pre class="wp-block-code"><code>$ sudo snap install pycharm-community --classic
$ sudo sudo apt install  pyqt5-dev-tools python3-pyqt5 qttools5-dev-tools</code></pre>



<p>到 File -&gt; Settings -&gt; Tools -&gt; External Tools 新增一個新的設定<br />先叫 PyUIC 吧</p>



<figure class="wp-block-image"><img decoding="async" src="https://lh6.googleusercontent.com/prjTsGWULvFAiBAjwqep2eUeuyGoKUyCXEcg6ilIuWb6s25SQEaXSEG597UumOzY3M9kZHOE8-ZVw-U6Zv8ATEHJkptQD7-dxNwgLUcmwJ8T9NlMv-Wih1xi3sdwO6s-wtJ0Okp0" alt=""/><figcaption>我都加好了</figcaption></figure>



<p>設定如下<br />Program : /usr/bin/pyuic5<br />Arguments :  $FileName$ -o $FileNameWithoutExtension$.py <br />Working Directory  : $ProjectFileDir$/$FileDirRelativeToProjectRoot$</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="697" height="760" src="https://blog.richliu.com/wp-content/uploads/2020/07/image.png" alt="" class="wp-image-4302" srcset="https://blog.richliu.com/wp-content/uploads/2020/07/image.png 697w, https://blog.richliu.com/wp-content/uploads/2020/07/image-275x300.png 275w" sizes="(max-width: 697px) 100vw, 697px" /></figure>



<p>接下來再新增一個，就叫 QT Designer <br /><br />Program : /usr/lib/x86_64-linux-gnu/qt5/bin/designer<br />Arguments :  $FileName$ <br />Working Directory : $ProjectFileDir$/$FileDirRelativeToProjectRoot$</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="692" height="763" src="https://blog.richliu.com/wp-content/uploads/2020/07/image-1.png" alt="" class="wp-image-4303" srcset="https://blog.richliu.com/wp-content/uploads/2020/07/image-1.png 692w, https://blog.richliu.com/wp-content/uploads/2020/07/image-1-272x300.png 272w" sizes="(max-width: 692px) 100vw, 692px" /></figure>



<p>這樣就可以在目錄下的 .ui 檔案上選 PyUIC 將 .ui 轉成 .py <br />然後選 QT Designer 修改 .ui 檔<br /><br />你看這樣很簡單吧</p>
<p>The post <a rel="nofollow" href="https://blog.richliu.com/2019/02/21/3879/pycharm-%e5%85%a7%e5%9f%b7%e8%a1%8c-qt-designer-%e5%92%8c-ui-%e8%bd%89-py/">PyCharm 內執行 QT Designer 和 ui 轉 py</a> appeared first on <a rel="nofollow" href="https://blog.richliu.com">richliu&#039;s blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.richliu.com/2019/02/21/3879/pycharm-%e5%85%a7%e5%9f%b7%e8%a1%8c-qt-designer-%e5%92%8c-ui-%e8%bd%89-py/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>python vim setting</title>
		<link>https://blog.richliu.com/2019/01/16/3364/python-vim-setting/</link>
					<comments>https://blog.richliu.com/2019/01/16/3364/python-vim-setting/#respond</comments>
		
		<dc:creator><![CDATA[richliu]]></dc:creator>
		<pubDate>Wed, 16 Jan 2019 08:03:40 +0000</pubDate>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[vim]]></category>
		<guid isPermaLink="false">https://blog.richliu.com/?p=3364</guid>

					<description><![CDATA[<p>忘了那邊找來的，不過覺得不錯用 將以下設定存到 /etc/vim/vimrc or ~/.vimrc " co [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.richliu.com/2019/01/16/3364/python-vim-setting/">python vim setting</a> appeared first on <a rel="nofollow" href="https://blog.richliu.com">richliu&#039;s blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>忘了那邊找來的，不過覺得不錯用</p>
<p>將以下設定存到 /etc/vim/vimrc or ~/.vimrc</p>


<pre class="wp-block-preformatted">" configure expanding of tabs for various file types
au BufRead,BufNewFile *.py set expandtab
au BufRead,BufNewFile *.c set noexpandtab
au BufRead,BufNewFile *.h set noexpandtab
au BufRead,BufNewFile Makefile* set noexpandtab
" --------------------------------------------------------------------------------
" configure editor with tabs and nice stuff...
" --------------------------------------------------------------------------------
set expandtab " enter spaces when tab is pressed
set textwidth=120 " break lines when line length increases
set tabstop=4 " use 4 spaces to represent tab
set softtabstop=4
set shiftwidth=4 " number of spaces to use for auto indent
set autoindent " copy indent from current line when starting a new line
 " make backspaces more powerfull
set backspace=indent,eol,start
 set ruler " show line and column number
syntax on " syntax highlighting
set showcmd " show (partial) command in status line </pre>



<p></p>
<p>The post <a rel="nofollow" href="https://blog.richliu.com/2019/01/16/3364/python-vim-setting/">python vim setting</a> appeared first on <a rel="nofollow" href="https://blog.richliu.com">richliu&#039;s blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.richliu.com/2019/01/16/3364/python-vim-setting/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[Gentoo] letsencrypt: acme==0.6.0.dev0 distribution was not found &#8230;</title>
		<link>https://blog.richliu.com/2016/06/12/1967/gentoo-letsencrypt-acme0-6-0-dev0-distribution-was-not-found/</link>
					<comments>https://blog.richliu.com/2016/06/12/1967/gentoo-letsencrypt-acme0-6-0-dev0-distribution-was-not-found/#respond</comments>
		
		<dc:creator><![CDATA[richliu]]></dc:creator>
		<pubDate>Sun, 12 Jun 2016 13:01:54 +0000</pubDate>
				<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[letsencrypt]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">https://blog.richliu.com/?p=1967</guid>

					<description><![CDATA[<p>今天碰到一個奇怪的問題 letsencrypt: acme==0.6.0.dev0 distribution  [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.richliu.com/2016/06/12/1967/gentoo-letsencrypt-acme0-6-0-dev0-distribution-was-not-found/">[Gentoo] letsencrypt: acme==0.6.0.dev0 distribution was not found &#8230;</a> appeared first on <a rel="nofollow" href="https://blog.richliu.com">richliu&#039;s blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>今天碰到一個奇怪的問題<br />
letsencrypt: acme==0.6.0.dev0 distribution was not found &#8230;<br />
<span id="more-1967"></span></p>
<p>原始訊息</p>
<p><code>letsencrypt --help<br />
Traceback (most recent call last):<br />
  File "/usr/lib/python-exec/python2.7/letsencrypt", line 5, in <module><br />
    from pkg_resources import load_entry_point<br />
  File "/usr/lib/python2.7/site-packages/pkg_resources/__init__.py", line 3080, in </module><module><br />
    @_call_aside<br />
  File "/usr/lib/python2.7/site-packages/pkg_resources/__init__.py", line 3066, in _call_aside<br />
    f(*args, **kwargs)<br />
  File "/usr/lib/python2.7/site-packages/pkg_resources/__init__.py", line 3093, in _initialize_master_working_set<br />
    working_set = WorkingSet._build_master()<br />
  File "/usr/lib/python2.7/site-packages/pkg_resources/__init__.py", line 653, in _build_master<br />
    return cls._build_from_requirements(__requires__)<br />
  File "/usr/lib/python2.7/site-packages/pkg_resources/__init__.py", line 666, in _build_from_requirements<br />
    dists = ws.resolve(reqs, Environment())<br />
  File "/usr/lib/python2.7/site-packages/pkg_resources/__init__.py", line 839, in resolve<br />
    raise DistributionNotFound(req, requirers)<br />
pkg_resources.DistributionNotFound: The 'acme==0.6.0.dev0' distribution was not found and is required by letsencrypt </module></code></p>
<p>這是 gcc 換 5.x 之後要重新 compile 一遍, 並且舊的 letsencrypt 改名叫 certbot<br />
<code>$ revdep-rebuild --library 'libstdc++.so.6' -- --exclude gcc<br />
$ emerge -avu certbot<br />
</code></p>
<p>這樣就可以了</p>
<p>原來的錯誤訊息是我要找的, 但是點進去卻是完全不同的標題和文章, 真是神祕<br />
ref<br />
<a href="https://forums.gentoo.org/viewtopic-t-1040792-view-next.html?sid=4972e0a3afe2ea82e21e32f98b3a0ab1" target="_blank" rel="noopener">emerge klibc fails with compiler-gcc5.h missing</a><br />
<a href="https://letsencrypt.org/getting-started/" target="_blank" rel="noopener">Letsencrypt Getting Started</a></p>
<p>The post <a rel="nofollow" href="https://blog.richliu.com/2016/06/12/1967/gentoo-letsencrypt-acme0-6-0-dev0-distribution-was-not-found/">[Gentoo] letsencrypt: acme==0.6.0.dev0 distribution was not found &#8230;</a> appeared first on <a rel="nofollow" href="https://blog.richliu.com">richliu&#039;s blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.richliu.com/2016/06/12/1967/gentoo-letsencrypt-acme0-6-0-dev0-distribution-was-not-found/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>自幹 dyndns</title>
		<link>https://blog.richliu.com/2014/10/09/1674/%e8%87%aa%e5%b9%b9-dyndns/</link>
					<comments>https://blog.richliu.com/2014/10/09/1674/%e8%87%aa%e5%b9%b9-dyndns/#respond</comments>
		
		<dc:creator><![CDATA[richliu]]></dc:creator>
		<pubDate>Wed, 08 Oct 2014 17:01:20 +0000</pubDate>
				<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[Network]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[UNIX]]></category>
		<category><![CDATA[Bind]]></category>
		<category><![CDATA[dyndns]]></category>
		<category><![CDATA[named]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[schtasks]]></category>
		<category><![CDATA[Update]]></category>
		<category><![CDATA[windows]]></category>
		<guid isPermaLink="false">http://blog.richliu.com/?p=1674</guid>

					<description><![CDATA[<p>之前好像免費的 dyndns 都收的差不多了, 好像很久沒有人提了. 今天心情還不錯, 就來架設自己的 dyn [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.richliu.com/2014/10/09/1674/%e8%87%aa%e5%b9%b9-dyndns/">自幹 dyndns</a> appeared first on <a rel="nofollow" href="https://blog.richliu.com">richliu&#039;s blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>之前好像免費的 dyndns 都收的差不多了, 好像很久沒有人提了.<br />
今天心情還不錯, 就來架設自己的 dyndns.<br />
主要可以參考這二篇</p>
<p><a href="http://phorum.study-area.org/index.php?topic=40717.0" target="_blank" rel="noopener">[分享] 用 BIND 架設 DDNS Server 提供 DDNS 服務 </a>及<br />
<a href="http://www.study-area.org/tips/ddns.htm" target="_blank" rel="noopener">動態 DNS 設定技巧</a><br />
<span id="more-1674"></span></p>
<p>上網看了一下, 大家寫的非常長, 不過如果架過 DNS, 其實也沒有這麼難, 實作上還算簡單的.<br />
至少比想像中簡單許多<br />
1. 在 /var/bind/pri/named.domain.com 中加入你想要做 dyndns 的 domain name</p>
<p style="padding-left: 30px;">ex:<br />
test A 0.0.0.0</p>
<p style="padding-left: 30px;">別忘了改 serial number</p>
<p>2. 到 /var/bind/dyn 下產生 key</p>
<p style="padding-left: 30px;"># dnssec-keygen -a HMAC-MD5 -b 512 -n USER test.domain.name.<br />
會產生二個檔案, 內容產不多</p>
<p>3. 將 key 內容 copy 到 bind 去</p>
<p style="padding-left: 30px;">將其中的 Ktest.domain.name.+123+45678.key 內的</p>
<p style="padding-left: 30px;">&#8220;test.domain.name. IN KEY 0 3 157 WH3pLphbwFlc/F8C1tbFcdzWRfcDdYWu00KBM5l2OE0rAVHzXFO+dahU SRrPKC0AMcbO6mwV4oVK94G9J5u9aw==<br />
放到 /etc/bind/named.conf 內,</p>
<p style="padding-left: 30px;">key test.domain.name. {<br />
algorithm HMAC-MD5;<br />
secret &#8220;WH3pLphbwFlc/F8C1tbFcdzWRfcDdYWu00KBM5l2OE0rAVHzXFO+dahU SRrPKC0AMcbO6mwV4oVK94G9J5u9aw==&#8221;;<br />
};</p>
<p>4. 修改 zone 的設定</p>
<p style="padding-left: 30px;">zone &#8220;domain.name&#8221; in {<br />
type master;<br />
file &#8220;pri/named.domain&#8221;;<br />
allow-query{ any; };</p>
<p style="padding-left: 30px;">update-policy {<br />
grant test.domain.name. name test.domain.name. A;<br />
};<br />
};</p>
<p>5. Restart bind</p>
<p style="padding-left: 30px;"># /etc/init.d/named restart</p>
<p>6. 測試 Update 是否成功<br />
使用 nsupdate 工具向 Primary DNS 做更新動作：</p>
<p>$ nsupdate -k Ktest.domain.name.+123+45678.key<br />
&gt; server ns.domain.name // 指定 Primary DNS<br />
&gt; update delete test.domain.name A // 先刪除舊資料<br />
&gt; update add test.domain.name 0 A 1.1.1.1 // 再新增資料<br />
&gt; send // 送出到 Primary DNS<br />
$ dig @ns.domain.name test.domain.name<br />
;; ANSWER SECTION:<br />
test.domain.name. 0 IN A 1.1.1.1</p>
<p>如果不成功, 可以看一下 /var/log , 然後看看是不是少了 /var/bind/pri/named.domain.com.jnl, 這個權限要加上去<br />
如果重啟之後, 出現 &#8220;response to SOA query was unsuccessful&#8221;, 那個 .jnl 的檔案砍了再重來就可以了, 好像是改了 SOA 就會錯亂.</p>
<p>這樣算完成一半, 上面第二個 Link 內有 Linux Update 的範例, 不過 Windows 怎麼辦呢? 像中華電信每幾天會換一次 IP, 所以自動更新的功能只好自己硬幹了. 而且 Windows PPPoE Disconnect/connected 時都不會有 event 可以呼叫 script 去執行, 所以就每一陣子執行一次 script 更新一下 DNS 資料, 不重要的 Service 這樣做還好, 重要的話可能就不行, 但是重要的也不會放 PPPoE 上吧 XD</p>
<p>自己硬幹有幾個選擇</p>
<p style="padding-left: 30px;">[X] DOS BASH : 這個很差, 可能抓不到 IP<br />
[X] Cygwin : 這個在我的 Windows XP 上根本跑不起來, 被防毒軟體擋到不能用 :&lt;<br />
[O] Python : 這個好, 什麼地方都可以用, 只要跑簡單的程式的話, 還是 python 安定.</p>
<p>所以就自己寫了一個小程式<br />
1. 程式碼放到 github , 存成 update.py<br />
https://github.com/richliu/dnsupdate</p>
<p>2. 產生 template file, script.txt 內容如下</p>
<p style="padding-left: 30px;">server ns.domain.name<br />
update delete test.domain.name A<br />
update add test.domain.name 0 A SERVER_NEW_IP<br />
send</p>
<p>3. 產生一個空的 ip.dat 檔案. (懶得檢查了, 所以就自己動手最快)</p>
<p>4. 寫一個 run.bat 內容是</p>
<p style="padding-left: 30px;">cd C:\TEST\<br />
C:\Python27\python.exe update.py</p>
<p>5. 下載 bind 執行檔 for windows 32bit</p>
<p><a href="http://www.isc.org/downloads/bind/" target="_blank" rel="noopener">  http://www.isc.org/downloads/bind/</a></p>
<p>解出所有的 .dll 檔, 和 dig 及 nsupdate 丟到同一個目錄, 如果是 windows 32 bit, 別忘了執行一下程式內的 vcredist_x86.exe, 這是 visual c++ 2005 dll .</p>
<p>6. 定時執行</p>
<p style="padding-left: 30px;">如果 IP 有變的話就會更新 dyndns, 因為用 windows, 所以採用的是 schtasks.<br />
相關的說明可以上 Microsoft <a href="http://technet.microsoft.com/en-us/library/cc725744.aspx" target="_blank" rel="noopener">Schtasks</a> 網站看<br />
用下面這個指令就可以讓 script 每 5 分鐘執行一次<br />
# schtasks /create /tn &#8220;Check IP&#8221; /tr c:\TEST\run.bat /sc minute /mo 5</p>
<p>大.功.告.成.</p>
<p>&nbsp;</p>
<p>The post <a rel="nofollow" href="https://blog.richliu.com/2014/10/09/1674/%e8%87%aa%e5%b9%b9-dyndns/">自幹 dyndns</a> appeared first on <a rel="nofollow" href="https://blog.richliu.com">richliu&#039;s blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.richliu.com/2014/10/09/1674/%e8%87%aa%e5%b9%b9-dyndns/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
