<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4479604189222772504</id><updated>2026-06-30T10:36:10.890+08:00</updated><category term="電子郵件管理"/><category term="Cisco"/><category term="WSS"/><category term="系統管理"/><category term="渡假"/><category term="Oracle"/><category term="XML"/><category term="程式設計"/><category term="AD系統管理"/><category term="IIS"/><category term="使用經驗"/><category term="當兵的點滴回憶"/><category term="網頁程式開發"/><title type='text'>  雨恩的生活日誌</title><subtitle type='html'>這個網誌的資訊只供本人備忘筆記使用，可能無法正確反應事實，因此可能沒有任何參考價值。若有任何錯誤，或因引用此網誌資訊所造成的問題或損失，本人無法負任何責任。任何版權或商標，其所有權皆屬於原所有者。對於引用他處文章，若有任何誤用，都是個人了解不清，先行致歉。</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>197</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-826966370752953876</id><published>2026-06-30T10:36:10.890+08:00</published><updated>2026-06-30T10:36:10.890+08:00</updated><title type='text'>排查IIS ASP.NET網站應用程式記實</title><content type='html'>&lt;p&gt;&amp;nbsp;事情發生在windows domain controller (DC)伺服器的硬碟故障導致我們直接放棄該台DC並將所有DC工作全部轉移到另一台DC之後。登入網域驗證的工作沒有問題的移轉了, 但問題出在DNS: client若使用DHCP取得IP的, 基本沒什麼問題。問題在固定IP的電腦或伺服器, 基本上若有變慢或卡住的情形, 檢查其DNS設定做更改就是。但有些情況是比較難排查的:&lt;/p&gt;&lt;p&gt;我們注意到內部一套使用ASP.NET開發的系統, 之前都流暢運行, 現在在登入或操作數分鐘之後, 會出現卡住10多秒的情形, 但之後又可以持續正常運行一段時間。&lt;/p&gt;&lt;p&gt;一開就懷疑是名稱解析問題, 但該伺服器的DNS已改成正確的, 狀況還是沒有改善。問Copilot意見，由它的建議中，找到查IIS Log的方法:&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h2&gt;📑 檢查 IIS 日誌&lt;/h2&gt;&lt;ol role=&quot;list&quot; start=&quot;1&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;strong style=&quot;white-space: pre-wrap;&quot;&gt;日誌位置&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul role=&quot;list&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;預設路徑：&lt;/span&gt;&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;程式碼&lt;/span&gt;&lt;button aria-expanded=&quot;true&quot; title=&quot;摺疊程式碼片段&quot; type=&quot;button&quot;&gt;&lt;svg fill=&quot;currentColor&quot; viewbox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M8.46967 4.21967C8.17678 4.51256 8.17678 4.98744 8.46967 5.28033L15.1893 12L8.46967 18.7197C8.17678 19.0126 8.17678 19.4874 8.46967 19.7803C8.76256 20.0732 9.23744 20.0732 9.53033 19.7803L16.7803 12.5303C17.0732 12.2374 17.0732 11.7626 16.7803 11.4697L9.53033 4.21967C9.23744 3.92678 8.76256 3.92678 8.46967 4.21967Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;rounded-b-xl bg-background-static-850 px-4 pb-1.5 dark:bg-background-static-900&quot;&gt;&lt;div style=&quot;white-space: pre;&quot;&gt;&lt;pre style=&quot;white-space: pre;&quot;&gt;&lt;code style=&quot;white-space: pre;&quot;&gt;%systemroot%\system32\LogFiles\W3SVC1\
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;（不同網站會有不同的 W3SVC 編號資料夾）&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;打開最可能的日誌檔後，複製全部的內容，再貼回給Copilot去分析。它告訴我幾個要注意的地方, 其中出現302重導, POST請求的問題, 可能是登入流程, session驗證, 或後端SQL查詢延遲。這讓我將注意力放到登入的部份, 確實問題是在登入或操作數分鐘之後, 會出現卡住10多秒的情形。而我們的ASP.NET應用程式, 也是在登入時必須和後端資料庫比對資料成功後才發給session。先看看是否連線到資料庫正常, 用tnsping:&lt;/p&gt;&lt;p&gt;C:\Documents and Settings\ops&amp;gt;tnsping xxx&lt;/p&gt;&lt;p&gt;TNS Ping Utility for 32-bit Windows: Version 9.2.0.1.0 - Production on 25-6月 -2
026 10:53:52&lt;/p&gt;&lt;p&gt;Copyright (c) 1997 Oracle Corporation.  All rights reserved.&lt;/p&gt;&lt;p&gt;已使用的參數檔案:&lt;/p&gt;&lt;p&gt;使用 TNSNAMES 介面程式來解析別名
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)
(HOST = tf-or11g.princo.com.tw)(PORT = 1521))) (CONNECT_DATA = (SERVER = SHARED)
(SERVICE_NAME = orclXDB)))
OK (0 msec)&lt;/p&gt;&lt;p&gt;Copilot說: &quot;你跑的 tnsping xxx 測試結果顯示 Oracle Net 連線非常快 (0 msec)，代表 網路、Listener、TNS 解析都沒有問題。這樣一來，IIS /salary/login.aspx 多次 302 延遲&lt;b&gt;就不是「連線建立」的問題，而更可能是 應用程式與 Oracle DB 互動的效能瓶頸&lt;/b&gt;。接下來可以從以下幾個角度深入檢查：&quot; 然後列了一大堆可能的檢查方向。我先試個人覺得比較有可能的:&lt;/p&gt;&lt;h3&gt;&lt;strong&gt;慢查詢 / Index 問題&lt;/strong&gt;&lt;/h3&gt;&lt;ul role=&quot;list&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;登入驗證通常會查詢使用者表，若缺少索引或 SQL 效能差，會造成延遲。&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;檢查：&lt;/span&gt;&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;sql&lt;button aria-expanded=&quot;true&quot; title=&quot;摺疊程式碼片段&quot; type=&quot;button&quot;&gt;&lt;svg fill=&quot;currentColor&quot; viewbox=&quot;0 0 24 24&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M8.46967 4.21967C8.17678 4.51256 8.17678 4.98744 8.46967 5.28033L15.1893 12L8.46967 18.7197C8.17678 19.0126 8.17678 19.4874 8.46967 19.7803C8.76256 20.0732 9.23744 20.0732 9.53033 19.7803L16.7803 12.5303C17.0732 12.2374 17.0732 11.7626 16.7803 11.4697L9.53033 4.21967C9.23744 3.92678 8.76256 3.92678 8.46967 4.21967Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;rounded-b-xl bg-background-static-850 px-4 pb-1.5 dark:bg-background-static-900&quot;&gt;&lt;div style=&quot;white-space: pre;&quot;&gt;&lt;pre&gt;&lt;code&gt;SELECT sql_id, executions, elapsed_time/executions AS avg_ms
FROM v$sql
WHERE sql_text LIKE &#39;%LOGIN%&#39;;&lt;br /&gt;&lt;br /&gt;SQL_ID        EXECUTIONS     AVG_MS
------------- ---------- ----------
059zr3n1302hh         10    14287.3
04zbxydx7zr42          1      15098&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Copilot看到這個結果後說: &quot;你查到的 SQL 結果非常關鍵：這代表登入相關的 SQL 平均執行時間 14~15 秒，這正好對應到 IIS /salary/login.aspx 出現的 10 秒以上延遲。也就是說，問題不是 Oracle Net 連線或 Dispatcher，而是 登入驗證 SQL 本身效能差。&quot;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;&lt;strong&gt;找出 SQL 內容&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;sql&lt;button aria-expanded=&quot;true&quot; title=&quot;摺疊程式碼片段&quot; type=&quot;button&quot;&gt;&lt;svg fill=&quot;currentColor&quot; viewbox=&quot;0 0 24 24&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M8.46967 4.21967C8.17678 4.51256 8.17678 4.98744 8.46967 5.28033L15.1893 12L8.46967 18.7197C8.17678 19.0126 8.17678 19.4874 8.46967 19.7803C8.76256 20.0732 9.23744 20.0732 9.53033 19.7803L16.7803 12.5303C17.0732 12.2374 17.0732 11.7626 16.7803 11.4697L9.53033 4.21967C9.23744 3.92678 8.76256 3.92678 8.46967 4.21967Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;rounded-b-xl bg-background-static-850 px-4 pb-1.5 dark:bg-background-static-900&quot;&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;SELECT sql_text
FROM v$sql
WHERE sql_id=&#39;059zr3n1302hh&#39;;&lt;br /&gt;&lt;br /&gt;INSERT INTO mgmt_db_dbNInstanceInfo_ecm
(BANNER, CHARACTERSET, DATABASE_NAME, DEFAULT_TEMP_TABLESPACE, DV_STATUS_CODE,
 ECM_SNAPSHOT_ID, GLOBAL_NAME, HOST_NAME, INSTANCE_NAME, LOGINS, LOG_MODE,
 NATIONAL_CHARACTERSET, OPEN_MODE, STARTUP_TIME)
VALUES (:1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13, :14)&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;可惜的是, 這個&amp;nbsp;&amp;nbsp;平均執行時間 14~15 秒的SQL, 並不是單純的登入驗證查詢而是不知道在何時觸發的管理性 INSERT! 因此這個方向不對。&lt;/p&gt;&lt;p&gt;Copilot也叫我去檢查v$lock裡是否有大量鎖定, 這也個條死巷子。&lt;/p&gt;&lt;p&gt;最後我問了Copilot一個問題:&amp;nbsp;&lt;b style=&quot;white-space: pre-wrap;&quot;&gt;&lt;u&gt;how to find the long rurn sql query?&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b style=&quot;white-space: pre-wrap;&quot;&gt;&lt;u&gt;它的回答, 給了我找到root cause的契機。&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;To identify &lt;/span&gt;&lt;strong style=&quot;white-space: pre-wrap;&quot;&gt;long‑running SQL queries&lt;/strong&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt; in Oracle, you can use several dynamic performance views. Here are the most effective approaches:&lt;/span&gt;&lt;/p&gt;&lt;div aria-labelledby=&quot;eDVm7S9JvtFMskqXt1goo-author&quot; data-content=&quot;ai-message&quot; data-tabster=&quot;{&amp;quot;groupper&amp;quot;:{&amp;quot;tabbability&amp;quot;:2},&amp;quot;focusable&amp;quot;:{}}&quot; data-testid=&quot;ai-message&quot; role=&quot;article&quot; tabindex=&quot;0&quot;&gt;&lt;div data-testid=&quot;ai-message-body&quot;&gt;&lt;div id=&quot;eDVm7S9JvtFMskqXt1goo-content-0&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;h2&gt;🔎 Methods to Find Long‑Running SQL&lt;/h2&gt;&lt;h3&gt;1. Active Sessions Currently Running&lt;/h3&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;sql&lt;button aria-expanded=&quot;true&quot; title=&quot;摺疊程式碼片段&quot; type=&quot;button&quot;&gt;&lt;svg fill=&quot;currentColor&quot; viewbox=&quot;0 0 24 24&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M8.46967 4.21967C8.17678 4.51256 8.17678 4.98744 8.46967 5.28033L15.1893 12L8.46967 18.7197C8.17678 19.0126 8.17678 19.4874 8.46967 19.7803C8.76256 20.0732 9.23744 20.0732 9.53033 19.7803L16.7803 12.5303C17.0732 12.2374 17.0732 11.7626 16.7803 11.4697L9.53033 4.21967C9.23744 3.92678 8.76256 3.92678 8.46967 4.21967Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;rounded-b-xl bg-background-static-850 px-4 pb-1.5 dark:bg-background-static-900&quot;&gt;&lt;div style=&quot;white-space: pre;&quot;&gt;&lt;pre&gt;&lt;code&gt;SELECT s.sid,
       s.serial#,
       s.username,
       s.machine,
       q.sql_id,
       q.sql_text,
       q.elapsed_time/1000000 AS elapsed_sec,
       q.executions
FROM   v$session s
JOIN   v$sql q ON s.sql_id = q.sql_id
WHERE  s.status = &#39;ACTIVE&#39;
ORDER BY elapsed_sec DESC;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;span style=&quot;white-space-collapse: preserve;&quot;&gt;我在網站應用程式卡住的時候去跑這支SQL查詢, 就看到一個可疑的長執行SQL: select * from dual@yyy&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;white-space-collapse: preserve;&quot;&gt;而yyy正是我們網站應用程式有用到的database link名稱, 再去檢查該資料庫連結名稱的定義, 發現其定義只是一個簡單的名稱, 應該是以前用手動指定在(現已故障放棄不用的)Domain Controller的DNS對應。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;white-space-collapse: preserve;&quot;&gt;因此, 將該資料庫連結名稱定義修改後, 問題就解決了。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;white-space-collapse: preserve;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;b style=&quot;white-space: pre-wrap;&quot;&gt;&lt;u&gt;&lt;br /&gt;&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/826966370752953876/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/826966370752953876?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/826966370752953876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/826966370752953876'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2026/06/iis-aspnet.html' title='排查IIS ASP.NET網站應用程式記實'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-8749612916239953947</id><published>2025-07-29T11:55:00.002+08:00</published><updated>2025-07-29T11:55:38.981+08:00</updated><title type='text'>Ubunt 24.04 加裝XFCE桌面環境</title><content type='html'>&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNsmmDFJhYPdgaZ2L5lUASWF0WnGb4zww0wRChrpnDLeHRGYp0fo5rWd6tSoSi8qygTTEbdvKUpc2RdA6KgM6YVyEYrosDyZO36Mvd7xDu-7b0hZ2dxAojx98OlAqArXVK1ONQRprjEF60n5TrSzz3u-xJ8ZODJ5YYnsBvfy-A0CK3povc_EcysMoxI3k/s1920/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-07-29%20104006.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1080&quot; data-original-width=&quot;1920&quot; height=&quot;360&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNsmmDFJhYPdgaZ2L5lUASWF0WnGb4zww0wRChrpnDLeHRGYp0fo5rWd6tSoSi8qygTTEbdvKUpc2RdA6KgM6YVyEYrosDyZO36Mvd7xDu-7b0hZ2dxAojx98OlAqArXVK1ONQRprjEF60n5TrSzz3u-xJ8ZODJ5YYnsBvfy-A0CK3povc_EcysMoxI3k/w640-h360/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-07-29%20104006.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&amp;nbsp;微軟的Copilot一直推薦我使用XFCE來取代GNOME桌面:&lt;blockquote&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;為了讓你在 XRDP 下獲得穩定的使用者體驗，尤其是在登入後不閃退、不依賴 GNOME 和 &lt;code&gt;systemd --user&lt;/code&gt;，我建議你使用 XFCE 或 MATE 桌面環境，並重新配置 session 啟動鏈條。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&amp;nbsp;我就信它一次, 來試試看:&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;🧰 1. 安裝 XFCE 桌面環境（推薦）&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;sudo apt update&amp;nbsp;&lt;/p&gt;&lt;p&gt;sudo apt install xfce4 xfce4-session xfce4-goodies dbus-x11
&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;為什麼選 XFCE：&lt;br /&gt;
它不依賴 &lt;code&gt;systemd --user&lt;/code&gt;，且在 XRDP 下表現穩定、資源消耗低。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;📝 2. 編輯 &lt;code&gt;/etc/xrdp/startwm.sh&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;請將內容改成如下：&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;#!/bin/sh&amp;nbsp;&lt;/p&gt;&lt;p&gt;. /etc/profile&lt;/p&gt;&lt;p&gt;&amp;nbsp;. ~/.profile&lt;/p&gt;&lt;p&gt;&amp;nbsp;exec startxfce4
&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;✅ 確保該檔案可執行：&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;sudo chmod +x /etc/xrdp/startwm.sh&lt;/p&gt;&lt;p&gt;&amp;nbsp;⚙️ 3. 設定 PAM 與 D-Bus 相容性（選用）&lt;/p&gt;
&lt;p&gt;確認 XRDP session 使用 PAM 載入環境：&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;sudo grep pam_systemd /etc/pam.d/xrdp-sesman || echo &quot;session required pam_systemd.so&quot;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;如果沒有該行，可加入：&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;echo &quot;session required pam_systemd.so&quot; | sudo tee -a /etc/pam.d/xrdp-sesman&lt;/p&gt;&lt;p&gt;&amp;nbsp;🧹 4. 清理殘留 &lt;code&gt;.Xauthority&lt;/code&gt; 及 lock file（首次修復建議）&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;sudo rm -f /tmp/.X11-unix/X*&amp;nbsp;&lt;/p&gt;&lt;p&gt;sudo rm -f /tmp/.X*-lock&amp;nbsp;&lt;/p&gt;&lt;p&gt;rm -f ~/.Xauthority&amp;nbsp;&lt;/p&gt;&lt;p&gt;touch ~/.Xauthority&amp;nbsp;&lt;/p&gt;&lt;p&gt;chown ops:ops ~/.Xauthority
&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;🚀 5. 重啟 XRDP&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;sudo systemctl restart xrdp&amp;nbsp;&lt;/p&gt;&lt;p&gt;sudo systemctl restart xrdp-sesman
&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;現在你重新連線後，應該會進入 XFCE 桌面，並且長時間不會被 session timeout 或閃退問題困擾。&lt;/p&gt;&lt;p&gt;--------------------------------------------&lt;/p&gt;&lt;p&gt;安裝 XFCE 桌面環境(sudo apt install xfce4 ...)後, 出現&quot;正在設定lightdm&quot;的對話框, 要我選default display manager, 我要選gdm3或lightdm? 同樣問Copilot, 它說lightdm。&lt;/p&gt;&lt;p&gt;--------------------------------------------&lt;/p&gt;&lt;p&gt;如上圖, XFCE果然簡潔有力, 就是古典的桌面, 但是我的要求是穏定, 其他再說, 所以先試看看一段時間。桌面的使用必須熟悉一下, 但似乎有些問題要先解決:&lt;/p&gt;&lt;p&gt;(1)&amp;nbsp;XFCE裡的終端機模擬程式, 無法開啓?&amp;nbsp;但是&quot;xfce終端機&quot;可以正常啓動?&amp;nbsp;在桌面下方的選單, 單選的&quot;終端機模擬程式&quot;, 其指令為exo-open --launch TerminalEmulator, 一直打不開?&lt;/p&gt;&lt;p&gt;🛠️ 解法：設定預設終端機程式給 &lt;code&gt;exo-open&lt;/code&gt;&lt;/p&gt;&lt;p&gt;XFCE 使用 &lt;code&gt;exo-preferred-applications&lt;/code&gt; 來設定「首選應用程式」，只要設定好 Terminal 類別即可：&lt;/p&gt;&lt;p&gt;✅ 方法一：圖形介面設定&lt;/p&gt;&lt;p&gt;


&lt;/p&gt;&lt;ol&gt;&lt;li&gt;在 XFCE 桌面上開啟 &lt;strong&gt;「設定」 → 「首選應用程式」&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;選擇「實用工具」分頁（Utilities）&lt;/li&gt;
&lt;li&gt;在「終端機模擬程式」選項中，選擇 &lt;code&gt;xfce4-terminal&lt;/code&gt; 或你想使用的其他程式（如 &lt;code&gt;xterm&lt;/code&gt;）&lt;/li&gt;
&lt;/ol&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhd6f2zciI-7NegAqS9QrjKnpetaE7q6f9jrrJzRENZUpyf5fVT9p9ll67eb_A_qth3ELkvRKFWDi66_0Rar_fw3Al3Hg6Ii4T0L5uHu9vQpcKlQGLUghFQxyXj_jkqAtSeKN_NMlMVBqG9CJBNN4B-Z7skwSg98w68pr7Ikv4qTx9bXHy68bKWkDsFNTc/s610/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7_2025-07-29_11-23-30.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;484&quot; data-original-width=&quot;610&quot; height=&quot;318&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhd6f2zciI-7NegAqS9QrjKnpetaE7q6f9jrrJzRENZUpyf5fVT9p9ll67eb_A_qth3ELkvRKFWDi66_0Rar_fw3Al3Hg6Ii4T0L5uHu9vQpcKlQGLUghFQxyXj_jkqAtSeKN_NMlMVBqG9CJBNN4B-Z7skwSg98w68pr7Ikv4qTx9bXHy68bKWkDsFNTc/w400-h318/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7_2025-07-29_11-23-30.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;這樣設好後, 左上角的&quot;應用程式&quot;下拉選單裡的&quot;終端機模擬程式&quot;, 和中間下方的&quot;終端機模擬程式&quot;圖示, 按下後才會出現正常的命令列工具(其實就是xfce終端機)。我也試過其他選項, 如GNOME終端機, 都不能正常啓動。&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(2) xfce中的firefox無法啓動? 觀察到log: Authorization required, but no authorization protocol specified Error: cannot open display: :10.0&lt;/div&gt;&lt;div&gt;&lt;p&gt;這個錯誤訊息表示 Firefox 嘗試在顯示器 &lt;code&gt;:10.0&lt;/code&gt; 上啟動，但 &lt;strong&gt;X11 授權失敗&lt;/strong&gt;。這在使用 XRDP、VNC 或 SSH X11 轉發時非常常見。&lt;/p&gt;&lt;p&gt;🛠️ 解決方法&lt;/p&gt;&lt;p&gt;✅ 1. 設定 &lt;code&gt;XAUTHORITY&lt;/code&gt; 環境變數&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;export XAUTHORITY=$HOME/.Xauthority
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;



&lt;/p&gt;&lt;p&gt;這告訴 Firefox 使用你目前使用者的 X 授權檔案。&lt;/p&gt;&lt;p&gt;✅ 4. 若使用 XRDP，請確認 session 啟動時有正確載入 &lt;code&gt;.Xauthority&lt;/code&gt;&lt;/p&gt;&lt;p&gt;你可以在 &lt;code&gt;~/.xsession&lt;/code&gt; 或 &lt;code&gt;startwm.sh&lt;/code&gt; 中加入：&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;


&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;export XAUTHORITY=$HOME/.Xauthority
&lt;/p&gt;&lt;/div&gt;&lt;div&gt;我選擇在startwm.sh中加入:export XAUTHORITY=$HOME/.Xauthority&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(3)&amp;nbsp;xfce會自己suspend? 一小段時間不使用後, 機器自己休眠了, 因為是要當伺服器用, 所以不能休眠。讓 XFCE 完全不自動休眠:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;⚙️ 停用 XFCE 的自動休眠功能&lt;/div&gt;&lt;div&gt;
&lt;p&gt;1. 關閉電源管理器的休眠設定&lt;/p&gt;
&lt;p&gt;打開 XFCE 電源管理器設定：&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;xfce4-power-manager-settings
&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;在「系統」分頁中：&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;將「閒置後執行動作」設為「無動作」&lt;/li&gt;
&lt;li&gt;將「蓋上筆電蓋子時」的動作也設為「無動作」&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;&lt;p&gt;🧱 阻止系統層級的 suspend 行為&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;systemctl&lt;/code&gt; 將休眠相關目標屏蔽：&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;這會防止任何服務或使用者觸發休眠、睡眠或混合睡眠。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;🖥️ 停用螢幕節能與 DPMS&lt;/p&gt;
&lt;p&gt;在 XFCE 啟動時執行以下命令，或加入到啟動項目中：&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;xset s off&amp;nbsp;&lt;/p&gt;&lt;p&gt;xset -dpms&amp;nbsp;&lt;/p&gt;&lt;p&gt;xset s noblank
&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;這些設定會停用螢幕保護、節能模式與自動關閉螢幕。&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;🧠 額外建議：確認 session 不會觸發 GNOME 或 systemd 的 idle suspend&lt;/p&gt;
&lt;p&gt;如果你有混合使用 GNOME 元件或 systemd-logind，請檢查 &lt;code&gt;/etc/systemd/logind.conf&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;[Login]&amp;nbsp;&lt;/p&gt;&lt;p&gt;IdleAction=ignore
&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;然後重啟 systemd-logind：&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;sudo systemctl restart systemd-logind
&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;這樣設定後，XFCE 就不會自動休眠了。&lt;/p&gt;&lt;p&gt;---------------------------------------------&lt;/p&gt;&lt;p&gt;所以, startwm.sh 變成:&lt;/p&gt;&lt;p&gt;if test -r /etc/profile; then&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt;	&lt;/span&gt;. /etc/profile&lt;/span&gt;&lt;/p&gt;&lt;p&gt;fi&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;if test -r ~/.profile; then&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt;	&lt;/span&gt;. ~/.profile&lt;/span&gt;&lt;/p&gt;&lt;p&gt;fi&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;export XAUTHORITY=$HOME/.Xauthority&lt;/p&gt;&lt;p&gt;xset s off&lt;/p&gt;&lt;p&gt;# xset -dpms&lt;/p&gt;&lt;p&gt;xset s noblank&lt;/p&gt;&lt;p&gt;exec startxfce4&lt;/p&gt;&lt;div&gt;----------------------------------------------&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/8749612916239953947/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/8749612916239953947?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/8749612916239953947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/8749612916239953947'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2025/07/ubunt-2404-xfce.html' title='Ubunt 24.04 加裝XFCE桌面環境'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNsmmDFJhYPdgaZ2L5lUASWF0WnGb4zww0wRChrpnDLeHRGYp0fo5rWd6tSoSi8qygTTEbdvKUpc2RdA6KgM6YVyEYrosDyZO36Mvd7xDu-7b0hZ2dxAojx98OlAqArXVK1ONQRprjEF60n5TrSzz3u-xJ8ZODJ5YYnsBvfy-A0CK3povc_EcysMoxI3k/s72-w640-h360-c/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-07-29%20104006.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-2922185174008945343</id><published>2025-07-24T16:48:00.003+08:00</published><updated>2025-07-29T10:50:47.390+08:00</updated><title type='text'>Ubuntu 24.04 XRDP+GNOME桌面狀況(黑畫面+閃退)</title><content type='html'>&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtpBfSZK0oIpnaqpqeCMsAHXgiXn16Me_R0tCUKLELwc6vlvlcRC1LXSyC4JdC0pX1SFd_oVsWgG7t0VOv_tTH9YeGfPUooRTnpTWc0LmzaUq9HRf0xCtwpq6C0hOrX0P8pSteJdB1DiULsNUZcKmlX9DIDq7AcnK8o04bfPrrHrzPbitUya25KOuxWZ0/s1920/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-07-29%20103911.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1080&quot; data-original-width=&quot;1920&quot; height=&quot;360&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtpBfSZK0oIpnaqpqeCMsAHXgiXn16Me_R0tCUKLELwc6vlvlcRC1LXSyC4JdC0pX1SFd_oVsWgG7t0VOv_tTH9YeGfPUooRTnpTWc0LmzaUq9HRf0xCtwpq6C0hOrX0P8pSteJdB1DiULsNUZcKmlX9DIDq7AcnK8o04bfPrrHrzPbitUya25KOuxWZ0/w640-h360/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-07-29%20103911.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&amp;nbsp;Ubuntu 24.04的GNOME桌面, 使用XRDP, 由遠端桌面工具登入時, 使用界面真的很棒。非常現代化的設計, 多個桌面任你增減, 應用程式隨你拖拉, 非常直覺的設計, 而且反應流暢快速, 令人愛不釋手。&lt;p&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; 但是我碰到許多問題, 一開始是用遠端桌面連線工具程式連入時, 畫面卡住, 只看到滑鼠遊標變成X, 就是所謂的黑畫面。找了一下, 有人說是將/etc/xrdp/startwm.sh加入以下幾行:&lt;/p&gt;&lt;p&gt;unset DBUS_SESSION_BUS_ADDRESS&lt;/p&gt;&lt;p&gt;unset XDG_RUNTIME_DIR&lt;/p&gt;&lt;p&gt;. $HOME/.profile&lt;/p&gt;&lt;div&gt;一開始, 還管用, 但不久又出狀況, 用遠端桌面連線工具程式連入時, 打完帳號密碼, 就立刻閃退。又找了一下, 網上有人說, 可以在client端的機器, 找default.rdp這個檔案, 把檔案的這行:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;use redirection server name:i:0&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;改成&lt;/div&gt;&lt;div&gt;use redirection server name:i:1&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;試了一下, 可以哦! 連進去了。&lt;/div&gt;&lt;div&gt;但好景不常, 沒幾天, 它自己斷線, 然後就再也連不進去了, 一直閃退!&amp;nbsp;&lt;/div&gt;&lt;div&gt;所以開始和Copilot一起找問題:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1. 先看/etc/xrdp/xrdp.ini, /etc/xrdp/sesman.ini, 沒什麼特別問題&lt;/div&gt;&lt;div&gt;2. 查看/var/log/xrdp-sesman.log, Copilot看完後說: &quot; XRDP session 啟動順利地完成使用者驗證並啟動了 Xorg，但在 window manager 啟動階段卻快速崩潰。這是造成 session 秒斷的主要原因。&quot; 然後它建議我檢查 /etc/xrdp/startwm.sh, 我就直接把這個.sh檔案內容給它看。它回答看起來就是預設的寫法, 依賴/etc/X11/Xsession來啓動桌面環境。並建議我大改/etc/xrdp/startwm.sh, 我覺得不知道在改什麼, 就告訴它, 重開機就可以連進去, 但一段時間後會斷線, 然後就連不進去。於是它要我試試:&lt;/div&gt;&lt;div&gt;&amp;nbsp; 2-1 檢查之前連線殘存的lock file&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; ls -la /tmp/.X11-unix/&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; ls -la /tmp/.X*-lock&lt;/div&gt;&lt;div&gt;&amp;nbsp; 2-2 session是否沒斷乾淨, 可以重開服務&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; sudo systemctl restart xrdp-sesman&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; sudo systemctl restart xrdp&lt;/div&gt;&lt;div&gt;&amp;nbsp; 2-3 session 顯示號與 Xserver 衝突, 查看&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; ps aux | grep X&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; 有的話, kill&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;3. 它要我看&amp;nbsp;&lt;u&gt;&lt;span style=&quot;color: #b45f06;&quot;&gt;~/.xsession-errors&lt;/span&gt;&lt;/u&gt;, 然後它告訴我: &quot;這些錯誤訊息揭露了 XRDP session 在 GNOME 桌面環境下啟動失敗的根本原因：缺少 dbus-launch 命令，導致整個 D-Bus 初始化鏈出錯，無法提供桌面環境所需的進程通訊功能。&quot; 它要我做以下動作:&lt;/div&gt;&lt;div&gt;&amp;nbsp; 3-1 安裝缺少的 dbus-x11 套件，這會提供 dbus-launch 命令&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; sudo apt install dbus-x11&lt;/div&gt;&lt;div&gt;&amp;nbsp; 3-2&amp;nbsp;安裝完成後，建議重啟 XRDP：&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; sudo systemctl restart xrdp&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; sudo systemctl restart xrdp-sesman&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;** 到這裡, 原本連不進去的, 就可以連進去了。接著我開始用力的測試XRDP, 用遠端桌面連線工具程式連入又登出, 又連入又登出, 就這樣試好幾次都可以。接著, 我用console登入, 再登出後。再使用遠端桌面連線工具程式嘗試連入, 結果又不行了! 我同樣再把&lt;u&gt;&lt;span style=&quot;color: #b45f06;&quot;&gt;~/.xsession-errors&lt;/span&gt;&lt;/u&gt;,&amp;nbsp;裡的錯誤訊息找出來給它看。它說: &quot;GNOME 需要 systemd --user 配合 D-Bus 啟動許多組件，缺失可能導致不穩定&quot;, 並建議安裝systemd-user, 以及檢查PAM:&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; cat /etc/pam.d/xrdp-sesman&lt;/div&gt;&lt;div&gt;這個檔要包含:&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; session required pam_systemd.so&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;** 以上動作做完後, 遠端桌面連線工具程式連入又登出, 都可以正常的再連入。但是console登入卻被警告使用者session已經存在, 不能登入, 除非強制將session關閉, 但如此可能造成一些問題。我試著按強制關閉, 卻沒反應。此時想到, 用:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;$ ps aux | grep X&lt;/div&gt;&lt;div&gt;gdm&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 26693&amp;nbsp; 0.0&amp;nbsp; 0.1 540508 82208 tty1&amp;nbsp; &amp;nbsp; &amp;nbsp;Sl+&amp;nbsp; 11:51&amp;nbsp; &amp;nbsp;0:00 /usr/bin/Xwayland :1024 -rootless -noreset -accessx -core -auth /run/user/124/.mutter-Xwaylandauth.577FA3 -listenfd 4 -listenfd 5 -displayfd 6 -initfd 7 -byteswappedclients&lt;/div&gt;&lt;div&gt;ops&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 27037&amp;nbsp; 0.0&amp;nbsp; 0.1 315300 74344 ?&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sl&amp;nbsp; &amp;nbsp;11:51&amp;nbsp; &amp;nbsp;0:00 /usr/lib/xorg/Xorg &lt;span style=&quot;color: #b45f06;&quot;&gt;:10&lt;/span&gt; -auth .Xauthority -config xrdp/xorg.conf -noreset -nolisten tcp -logfile .xorgxrdp.%s.log&lt;/div&gt;&lt;div&gt;ops&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 28353&amp;nbsp; 0.0&amp;nbsp; 0.1 314792 74016 ?&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sl&amp;nbsp; &amp;nbsp;11:52&amp;nbsp; &amp;nbsp;0:00 /usr/lib/xorg/Xorg &lt;span style=&quot;color: #b45f06;&quot;&gt;:11&lt;/span&gt; -auth .Xauthority -config xrdp/xorg.conf -noreset -nolisten tcp -logfile .xorgxrdp.%s.log&lt;/div&gt;&lt;div&gt;ops&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 43840&amp;nbsp; 0.0&amp;nbsp; 0.0&amp;nbsp; &amp;nbsp;6924&amp;nbsp; 2016 pts/0&amp;nbsp; &amp;nbsp; S+&amp;nbsp; &amp;nbsp;13:32&amp;nbsp; &amp;nbsp;0:00 grep --color=auto X&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;明顯可以看到session 顯示號10, 11兩個行程都還在, 並沒有因為遠端桌面連線登出而消失。所以就kill:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;$ sudo kill 28353&lt;/div&gt;&lt;div&gt;$ sudo kill 27037&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;此時由console就可以正常的登入了。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;***確實, XRDP和GNOME桌面環境的配合, 還不太穩定。不像SSH這般的穩定, 幾乎沒有出問題。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;----------------&lt;/div&gt;&lt;div&gt;結論:&lt;/div&gt;&lt;div&gt;----------------&lt;/div&gt;&lt;div&gt;1. 主要是XRDP session出問題, 可查看其log:&amp;nbsp;&amp;nbsp;&lt;u&gt;&lt;span style=&quot;color: #b45f06;&quot;&gt;~/.xsession-errors&lt;/span&gt;&lt;/u&gt;&lt;/div&gt;&lt;div&gt;2. dbus-x11套件要安裝&lt;/div&gt;&lt;div&gt;3. PAM設定要看一下&lt;/div&gt;&lt;div&gt;4. session 顯示號行程是否卡住, 可以用ps aux | grep X看, 有必要可kill&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/2922185174008945343/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/2922185174008945343?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/2922185174008945343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/2922185174008945343'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2025/07/ubuntu-2404-xrdp.html' title='Ubuntu 24.04 XRDP+GNOME桌面狀況(黑畫面+閃退)'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtpBfSZK0oIpnaqpqeCMsAHXgiXn16Me_R0tCUKLELwc6vlvlcRC1LXSyC4JdC0pX1SFd_oVsWgG7t0VOv_tTH9YeGfPUooRTnpTWc0LmzaUq9HRf0xCtwpq6C0hOrX0P8pSteJdB1DiULsNUZcKmlX9DIDq7AcnK8o04bfPrrHrzPbitUya25KOuxWZ0/s72-w640-h360-c/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-07-29%20103911.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-141762622219408153</id><published>2025-07-17T10:28:00.000+08:00</published><updated>2025-07-17T10:28:00.407+08:00</updated><title type='text'>Windows AD裡若有多台DC, 當其中一台出現問題時, 解決過程! (考古文)</title><content type='html'>&lt;p&gt;&amp;nbsp;沒錯! 2025年了, 還在用Windows 2003 server的AD網域。所以, 最新版的Windows AD應該已經不會有這些問題了吧! 我不知道! 但是windows 2003的AD, 就已經可以有多台DC, 當然是為了防止單一台主機故障, 我們辛苦一筆一筆建立的使用者帳號就不見了。有了多台DC, 就可以把這些帳號資料同時存在不同的DC, 萬一有一台機器壞了, 還有其他DC保存個這些資料。&lt;/p&gt;&lt;p&gt;&amp;nbsp; 那麼平常使用AD帳號登入機器時, 自然也是去DC查詢帳號密碼對不對。是不是多台DC環境下, 只要有一台DC正常運作, 就可以了呢? 很多人都會理所當然的這麼想的, 但在2003, 其實不是這樣的。我們有一台主機, 在登入畫面, 當選擇登入AD網域時, 一直出現 &quot;無法登入, 因為無法連線到網域&quot; 的錯誤訊息。因為之前已經檢查了相關主機狀況, 所以我知道多台DC中有一台有點問題。它出現了以下幾個徵狀:&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; 1. 在Active Directory使用者及電腦, 要查找使用者時出現問題&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; 2. 查看事件檢視器的目錄服務分類, 看到一些複寫的錯誤及警告, 例如:&lt;/p&gt;&lt;p&gt;------------------------------------------------------------------------------------------------------------------------&lt;/p&gt;&lt;p&gt;這個伺服器是下列 FSMO 角色的擁有者，但並不認為它是有效 的。對於含有 FSMO 的磁碟分割，這個伺服器自從重新啟動後即 未以任何它的協力電腦成功複寫過。複寫錯誤正阻礙這個角色的 確認。&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;要求連絡 FSMO 操作主機的操作將會失敗直到這個問題被更正 為止。&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;FSMO 角色: CN=RID Manager$,CN=System,DC=princo,DC=com,DC=tw&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;使用者動作:&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;1. 初始同步處理是系統啟動時所做的第一個早期複寫，初始 同步處理失敗可能說明了為什麼無法確認 FSMO 角色。這個程序 已在 KB article 305476 中說明。&amp;nbsp;&lt;/p&gt;&lt;p&gt;2. 這個伺服器擁有一 或多個複寫協力電腦，而所有這些協力電腦的複寫都將失敗。 請使用命令 repadmin /showrepl 來顯示複寫錯誤，更正有問題 的錯誤。例如，阻礙複寫成功的問題可能在 IP 連線能力，DNS 名稱解析或安全性驗證。&amp;nbsp;&lt;/p&gt;&lt;p&gt;3. 在所有複寫協力電腦全都關閉是預期發生 (可能因為維護 或從嚴重損毀中修復) 的稀有狀況中，您可以強迫確認角色。這 可以經由使用 NTDSUTIL.EXE 拿取角色給相同的伺服器來達到。 這可以使用 http://support.microsoft.com 上 KB articles 255504 和 324801 中所提供的步驟來達到。&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;下列操作可能會受影響:&amp;nbsp;&lt;/p&gt;&lt;p&gt;架構: 您將不再能夠修改這個樹系的架構。&amp;nbsp;&lt;/p&gt;&lt;p&gt;網域命名: 您將不再能夠從這個樹系新增或移除網域。&amp;nbsp;&lt;/p&gt;&lt;p&gt;PDC: 您將不再能夠執行諸如群組原則更新和非 Active Directory 帳戶密碼重設之類的主要網域控制站操作。&amp;nbsp;&lt;/p&gt;&lt;p&gt;RID: 您將不再能夠為新使用者帳戶、電腦帳戶或安全性群組 配置新的安全性識別元。&amp;nbsp;&lt;/p&gt;&lt;p&gt;基礎結構: 諸如萬用群組成員資格之類的跨網域名稱參照將 無法正確地更新，如果參照目標物件已移動或重新命名。&lt;/p&gt;&lt;p&gt;------------------------------------------------------------------------------------------------------------------------&lt;/p&gt;&lt;p&gt;以及:&lt;/p&gt;&lt;p&gt;-------------------------------------------------------------------------------------------------------------------------&lt;/p&gt;&lt;p&gt;這是本機網域控制站上，下列目錄磁碟分割的複寫狀態。&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;目錄磁碟分割:&lt;/p&gt;&lt;p&gt;DC=princo,DC=com,DC=tw&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;本機網域控制站最近並未從一些網域控制站收到複寫資訊。 顯示出的網域控制站計數，分成下列的間隔。&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;超過 24 小時:&lt;/p&gt;&lt;p&gt;2&amp;nbsp;&lt;/p&gt;&lt;p&gt;超過一週:&lt;/p&gt;&lt;p&gt;2&amp;nbsp;&lt;/p&gt;&lt;p&gt;超過一個月:&lt;/p&gt;&lt;p&gt;2&amp;nbsp;&lt;/p&gt;&lt;p&gt;超過兩個月:&lt;/p&gt;&lt;p&gt;2&amp;nbsp;&lt;/p&gt;&lt;p&gt;超過標記存留時間:&lt;/p&gt;&lt;p&gt;0&amp;nbsp;&lt;/p&gt;&lt;p&gt;標記存留時間 (天):&lt;/p&gt;&lt;p&gt;180&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;未及時複寫的網域控制站可能會發生錯誤。它可能會遺失密碼變更，並且無法驗證。未在標記存 留時間內進行複寫的 DC 可能已遺失某些物件的刪除，在重新調整之前，它將被自動中止以後的 複寫操作。&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;如果要依照名稱來識別網域控制站，請安裝包含在安裝 CD 中的支援工具，然後執行 dcdiag.exe。&amp;nbsp;&lt;/p&gt;&lt;p&gt;您也可以使用支援工具 repadmin.exe 來顯示樹系中網域控制站的複寫延遲。 命令為 &quot;repadmin /showvector /latency &amp;lt;partition-dn&amp;gt;&quot;。&lt;/p&gt;&lt;div&gt;------------------------------------------------------------------------------------------------------------------------&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;針對&quot;無法登入, 因為無法連線到網域&quot; 的錯誤訊息, 我當然問了AI, 它給我很多可能的問題原因和查找方法, 包括網路是否斷線, DNS查找是否正常等。這些, 我都已經排除了, 所以我直接告訴AI, 都不是這些問題, 而是多台DC中的一台壞了, 而那台要登入的主機, 那台DC不選, 偏要選壞掉的DC來查找登入資訊。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; 這就是Windows 2003的AD網域, 最令人不能理解的地方了。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; 我即然已經知道是有某台DC出問題, 那麼把它修好就是了。但不希望使用者等待我修護, 最直接的方式, 就是先將壞掉的DC關機。然後, 使用者再重新登入他的主機, 就會看到原本直接立刻跳出錯誤訊息的情況, 變成等待一會後, 就成功登入了。由行為來看, 問題並不在AD, 而昰要登入的主機(剛好也是Windows 2003), 為什麼不會(聰明一點)自動去試另一台DC? 而是固著在一台有問題的DC, 直到那台DC被關機?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; 使用者問題排除後, 我如何修這台出問題的DC? 因為查了一下, 發現是複寫失敗太久了(標記存留時間 =180天), 可能遺失某些物件的刪除, 等等的。我並沒有把握可以完整的修好它, 所以就選擇簡單一些的方法: &quot;把該台DC降級&quot;, 然後以後有必要, 再考慮是否把它升級回去。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; 但因為該台DC和其他正常的DC連線已經有問題, 所以用dcpromo指令, 做降級動作時, 會無法成功, 因為它要先連回AD, 做清除自己這個DC的資訊。這時候AI幫上忙了:&lt;/div&gt;&lt;div&gt;--------------------------------------------------------------------------------------------------------------------------&lt;/div&gt;&lt;div&gt;&lt;p&gt;在 Windows Server 2003 中，如果你使用 &lt;code&gt;dcpromo&lt;/code&gt; 降級網域控制站（DC）時遇到錯誤，例如無法聯繫其他 DC 或複製失敗，可以考慮使用 &lt;strong&gt;強制移除（/forceremoval）&lt;/strong&gt; 的方式跳過某些檢查。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;🛠️ 使用 &lt;code&gt;dcpromo /forceremoval&lt;/code&gt; 強制降級&lt;/p&gt;
&lt;p&gt;這個指令會將 DC 降級為成員伺服器，即使它無法與其他 DC 通訊：&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;dcpromo /forceremoval
&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;⚠️ 注意：這不會清除 Active Directory 中的該 DC 資料，會留下「孤立的 metadata」，你必須在其他健康的 DC 上手動清理。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;🧹 強制降級後的清理步驟&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;ol style=&quot;text-align: left;&quot;&gt;&lt;li&gt;&lt;strong&gt;清除 AD metadata&lt;/strong&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;在其他 DC 上執行：&lt;/li&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;ntdsutil
metadata cleanup
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;選取要移除的 DC，並執行 &lt;code&gt;remove selected server&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;strong&gt;移除 DNS 記錄&lt;/strong&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;刪除該 DC 的 A 記錄、SRV 記錄、反向查詢記錄&lt;/li&gt;
&lt;li&gt;檢查 &lt;code&gt;_msdcs&lt;/code&gt;、&lt;code&gt;_sites&lt;/code&gt; 等區域是否仍有殘留&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;strong&gt;移除 AD Sites and Services 中的伺服器物件&lt;/strong&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;li&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;📌 額外提醒&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;若該 DC 擁有 FSMO 角色，請先轉移或在其他 DC 上「強制接管（seize）」角色&lt;/li&gt;
&lt;li&gt;若該 DC 是 Global Catalog 或 DNS Server，也需在其他 DC 上重新設定&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;&lt;/div&gt;&lt;div&gt;-----------------------------------------------------------------------------------------------------------------&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; 所以, 做法是先找故障DC是否有 FSMO 角色, 若有則強制接管（seize）該角色, 還好我的情況是只有一個RID master。由另一台正常的DC先行強制接管後, 就去把故障DC降級, 接著還要去清一些AD metadata。這樣就暫時解決這個問題了。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; 至於如何查找 FSMO 角色及強制接管這些角色, 就問AI就可以了:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;------------------------------------------------------------------------------------------------------------------&lt;/div&gt;&lt;div&gt;&lt;p&gt;🛠️ 使用 &lt;code&gt;netdom&lt;/code&gt; 查詢 FSMO 角色分布&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;netdom query fsmo
&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;這個指令會列出目前網域中五個 FSMO 角色的持有者：&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;p&gt;FSMO 角色&lt;/p&gt;&lt;/th&gt;&lt;th&gt;&lt;p&gt;功能說明&lt;/p&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;p&gt;Schema Master&lt;/p&gt;&lt;/td&gt;&lt;td&gt;&lt;p&gt;控管 AD 架構的變更&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;Domain Naming Master&lt;/p&gt;&lt;/td&gt;&lt;td&gt;&lt;p&gt;控管網域新增/移除&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;RID Master&lt;/p&gt;&lt;/td&gt;&lt;td&gt;&lt;p&gt;分配 RID 給 DC，用於建立 SID&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;PDC Emulator&lt;/p&gt;&lt;/td&gt;&lt;td&gt;&lt;p&gt;模擬舊版 PDC，處理密碼同步與時間同步&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;p&gt;Infrastructure Master&lt;/p&gt;&lt;/td&gt;&lt;td&gt;&lt;p&gt;更新跨網域物件參照資訊&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;✅ &lt;code&gt;netdom&lt;/code&gt; 工具包含在 &lt;strong&gt;Windows Server 2003 Support Tools&lt;/strong&gt; 中，請確認已安裝。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;🛠️ 強制接管 RID Master 的步驟&lt;/p&gt;
&lt;p&gt;請在你要接管角色的 DC 上執行以下操作：&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;&lt;strong&gt;開啟命令提示字元&lt;/strong&gt;&lt;/li&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;ntdsutil
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;&lt;strong&gt;進入 FSMO 管理模式&lt;/strong&gt;&lt;/li&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;roles
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;&lt;strong&gt;建立連線到目標 DC（你要接管角色的 DC）&lt;/strong&gt;&lt;/li&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;connections
connect to server &amp;lt;你的DC名稱&amp;gt;
quit
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;&lt;strong&gt;執行強制接管 RID Master&lt;/strong&gt;&lt;/li&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;seize rid master
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;&lt;strong&gt;完成後退出工具&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;quit
quit
&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;------------------------------------------------------------------------------------------------------------------&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; 同樣, 清除AD metadata, 也是問AI:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;-------------------------------------------------------------------------------------------------------------------&lt;/div&gt;&lt;div&gt;&lt;p&gt;🧹 使用 &lt;code&gt;ntdsutil&lt;/code&gt; 清除 AD metadata 的步驟&lt;/p&gt;
&lt;p&gt;請在健康的 DC 上執行以下操作：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;開啟命令提示字元&lt;/strong&gt;&lt;/li&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;ntdsutil
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;&lt;strong&gt;進入 metadata cleanup 模式&lt;/strong&gt;&lt;/li&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;metadata cleanup
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;&lt;strong&gt;建立連線到本機或其他 DC&lt;/strong&gt;&lt;/li&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;connections
connect to server &amp;lt;你的DC名稱&amp;gt;
quit
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;&lt;strong&gt;選擇要移除的 DC&lt;/strong&gt;&lt;/li&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;select operation target
list domains
select domain &amp;lt;編號&amp;gt;
list sites
select site &amp;lt;編號&amp;gt;
list servers in site
select server &amp;lt;編號&amp;gt;
quit
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;&lt;strong&gt;移除選定的 DC&lt;/strong&gt;&lt;/li&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;remove selected server
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;&lt;strong&gt;退出工具&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;


&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;quit
quit
&lt;/p&gt;&lt;p&gt;📋 清理後的額外步驟&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Active Directory Sites and Services&lt;/strong&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;刪除該 DC 的 NTDS Settings 與 Server 物件&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;strong&gt;Active Directory Users and Computers&lt;/strong&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;刪除該 DC 的電腦帳戶（位於 Domain Controllers OU）&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;strong&gt;DNS 管理主控台&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;

&lt;/p&gt;&lt;ul&gt;&lt;li&gt;移除該 DC 的 A、SRV、PTR 記錄，特別是 &lt;code&gt;_msdcs&lt;/code&gt; 區域&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;-----------------------------------------------------------------------------------------------------------------&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; 雖然, Windows 2003是個老系統了, 這些問題別人肯定也碰過, 微軟的文件也是會有的。但是, 查找文件還是很花時間精神的。有了AI的協助, 要下什麼指令, 或找問題, 會更有效率。但是人類的判斷能力還是更好一些的, AI受限於我們輸入給它的資訊, 不見得看得到全貌。但是透過多次的來回問答, AI給了我許多協助, 得以更快的解決問題。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/141762622219408153/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/141762622219408153?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/141762622219408153'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/141762622219408153'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2025/07/windows-addc.html' title='Windows AD裡若有多台DC, 當其中一台出現問題時, 解決過程! (考古文)'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-7936371362418914532</id><published>2025-07-10T18:06:00.002+08:00</published><updated>2025-07-10T18:07:02.884+08:00</updated><title type='text'>在Windows 2003 server裡備份檔案, 使用ShadowSpawn + robocopy (考古文)</title><content type='html'>&lt;p&gt;&amp;nbsp;時光來到2025, 還在用Windows 2003 server, 大家就知道我的年資不少了。反正, 基於各種原因, 就是要用Windows 2003就對了。而且有備份檔案的需求, 上網找了一下可能的方案, 發現robocopy有不少愛好者, 評價很好。所以就想用, 而robocopy在windows 2003是透過resource kit提供。沒想到微軟的網站上, 已經找不到這個resource kit了, 所幸在Archive網站仍然可以找到。&lt;a href=&quot;https://archive.org/details/rktools&quot; target=&quot;_blank&quot;&gt;Windows 2003 Resource Kit x86 Internet Archive的連結&lt;/a&gt;&lt;/p&gt;&lt;p&gt;注意一下, 似乎只支援x86, 還好的是我使用的那台機器是x86。安裝方法很簡單, 下載下來的 rktools.exe檔直接執行, 然後一直下一步就可以了。預設會在C:\Program Files\Windows Resource Kits\Tools目錄下安裝許多工具程式, 其中也包括robocopy。&lt;/p&gt;&lt;p&gt;Robocopy的使用方法, 可以參考這個網站:&amp;nbsp;&lt;a href=&quot;https://www.cnblogs.com/liangwang/p/5340612.html&quot; target=&quot;_blank&quot;&gt;Robocopy使用詳例&lt;/a&gt;&lt;/p&gt;&lt;p&gt;**********************************************************&lt;/p&gt;&lt;p&gt;接著, 我發現了一件事: 有些檔案因為被鎖定, 所以一直沒有被robocopy備份到! 才想到要做Shadow copy! 又研究了一下, 發現ShadowSpawn的評價不錯, 它的網址:&amp;nbsp;&lt;a href=&quot;https://github.com/candera/shadowspawn&quot; target=&quot;_blank&quot;&gt;Candera/shadowspawn&lt;/a&gt;&amp;nbsp;是GitHub的一個公開專案, 可是專案owner Candera說已經十多年沒認真使用Windows平台了, 目前也沒心力再支援這個專案了, 也希望有心人可以fork它的專案來接手維護。而且, 之前的已編譯好的可執行程式目錄也不見了。所以只能自己編譯了(還好有source code), 但我試了一下, 發現我編出來的程式, 沒辦法在Windows 2003上面跑, 因為使用的微軟開發環境太新了!&amp;nbsp;&lt;/p&gt;&lt;p&gt;所幸, Candera有指出明路:&amp;nbsp;&lt;a href=&quot;https://github.com/candera/shadowspawn/issues/30&quot; target=&quot;_blank&quot;&gt;關於可在Windows 2003執行的ShadowSpawn可以在那裡找的討論文&lt;/a&gt;, 所以下載這支程式, 不用安裝, 直接放到HD, 再安裝vcredist-2010_x86.exe (如果原本沒裝過的話), 就可以了。試了一下, 可以順利執行! 但好像路徑名稱和中文不太合, 用英文路徑名就很順了。&lt;/p&gt;&lt;p&gt;** 警語: 是說, 我一直覺得不是由官方網站下載的程式, 安全性很令人擔心! 反正, 我先試試, 出了問題再來報告。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/7936371362418914532/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/7936371362418914532?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/7936371362418914532'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/7936371362418914532'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2025/07/windows-2003-server-shadowspawn-robocopy.html' title='在Windows 2003 server裡備份檔案, 使用ShadowSpawn + robocopy (考古文)'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-8440463070217633650</id><published>2025-07-08T18:04:00.002+08:00</published><updated>2025-07-09T10:16:55.703+08:00</updated><title type='text'>在Ubuntu 24.04上使用nsd安裝一台Authoritative DNS Server</title><content type='html'>&lt;p&gt;&amp;nbsp;我發現安裝Ubuntu 24.04 Server後預設會有systemd-resolved service在跑, 使用netstat -l指令查看, 會看到127.0.0.53之類的socket出現, 還有使用ls -l /etc/resolv.conf, 會發現這個檔案變成軟連結。問了Copilot, 它說: &quot;127.0.0.53 是 Linux 系統（特別是使用 systemd 的發行版，如 Ubuntu）中 systemd-resolved 的本地 DNS stub resolver。它的作用是作為本機 DNS 中介，將應用程式的查詢轉發給實際的上游 DNS 伺服器。&quot;而systemd-resolved的上遊是那台DNS server呢? 應該是放在 /etc/systemd/resolved.conf 這個設定檔, 這個檔可以如下設定:&lt;/p&gt;&lt;p&gt;[Resolve]&lt;/p&gt;&lt;div&gt;&lt;div&gt;DNS=8.8.8.8&lt;/div&gt;&lt;div&gt;FallbackDNS=1.1.1.1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;然後, 下指令:&lt;/div&gt;&lt;div&gt;sudo systemctl restart systemd-resolved&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;重啓systemd-resolved, 應該就可以正常的ping的到主機名稱了。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp;問題是, 我要安裝nsd時, 會發現port 53已經被佔用, 不能安裝了。所以第一個動作, 我必須先禁用systemd-resolved, 改回使用原本的/etc/resolv.conf檔的老方法。Copilot告訴我的詳細作法:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;-------------------------------------------------------------------------------------------------------&lt;/div&gt;&lt;div&gt;&lt;div&gt;關閉 systemd-resolved 的完整步驟：&lt;/div&gt;&lt;div&gt;- 停止並禁用服務&lt;/div&gt;&lt;div&gt;sudo systemctl disable --now systemd-resolved&lt;/div&gt;&lt;div&gt;- 移除 /etc/resolv.conf 的符號連結（symbolic link）&lt;/div&gt;&lt;div&gt;預設這個檔案其實是連到 /run/systemd/resolve/stub-resolv.conf&lt;/div&gt;&lt;div&gt;sudo rm /etc/resolv.conf&lt;/div&gt;&lt;div&gt;- 建立一份你自己的 resolv.conf 檔案&lt;/div&gt;&lt;div&gt;你可以手動指定 DNS，例如使用 Google DNS：&lt;/div&gt;&lt;div&gt;echo &quot;nameserver 8.8.8.8&quot; | sudo tee /etc/resolv.conf&lt;/div&gt;&lt;div&gt;echo &quot;nameserver 1.1.1.1&quot; | sudo tee -a /etc/resolv.conf&lt;/div&gt;&lt;div&gt;- ✅ 確認你的設定生效&lt;/div&gt;&lt;div&gt;執行：&lt;/div&gt;&lt;div&gt;cat /etc/resolv.conf&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;- 確認內容是你剛剛設定的 DNS。&lt;/div&gt;&lt;div&gt;📌 提醒一下：&lt;/div&gt;&lt;div&gt;關掉 systemd-resolved 之後，你系統上的某些網路管理工具（如 NetworkManager）如果沒有特別設定，可能會重新覆蓋 /etc/resolv.conf。&lt;/div&gt;&lt;/div&gt;&lt;div&gt;-------------------------------------------------------------------------------------------------------&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;為了避免/etc/resolv.conf再被別的工具覆蓋, Copilot教的方法:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;=============================================================&lt;/div&gt;&lt;div&gt;&lt;div&gt;方法一：使用 chattr 鎖定 resolv.conf&lt;/div&gt;&lt;div&gt;這個方法簡單又有效，適合手動管理 DNS。&lt;/div&gt;&lt;div&gt;- 確保 resolv.conf 已存在並正確設定&lt;/div&gt;&lt;div&gt;cat /etc/resolv.conf&lt;/div&gt;&lt;div&gt;- 例如，內容應該類似：&lt;/div&gt;&lt;div&gt;nameserver 8.8.8.8&lt;/div&gt;&lt;div&gt;nameserver 1.1.1.1&lt;/div&gt;&lt;div&gt;- 鎖定該檔案以防修改&lt;/div&gt;&lt;div&gt;sudo chattr +i /etc/resolv.conf&lt;/div&gt;&lt;div&gt;- 這會把檔案設成不可修改（immutable）。&lt;/div&gt;&lt;div&gt;- 如果日後你想修改內容，請先移除鎖定：&lt;/div&gt;&lt;div&gt;sudo chattr -i /etc/resolv.conf&lt;/div&gt;&lt;div&gt;⚙️ 方法二：調整 NetworkManager 設定（如果你有用它）如果你的系統有安裝 NetworkManager，可以這樣讓它不要自動控制 DNS 設定。- 編輯設定檔：&lt;/div&gt;&lt;div&gt;sudo nano /etc/NetworkManager/NetworkManager.conf&lt;/div&gt;&lt;div&gt;- 在 [main] 區段底下加一行：&lt;/div&gt;&lt;div&gt;dns=none&lt;/div&gt;&lt;div&gt;- 重新啟動 NetworkManager：&lt;/div&gt;&lt;div&gt;sudo systemctl restart NetworkManager&lt;/div&gt;&lt;div&gt;- 然後再次手動建立 /etc/resolv.conf（就像你之前做的那樣）。&lt;/div&gt;&lt;div&gt;🧠 小叮嚀：使用 chattr +i 是最強制、也最不容易出錯的方法，但如果你未來會透過圖形介面或 DHCP 自動取得 DNS，那就建議使用方法二來保持彈性。&lt;/div&gt;&lt;/div&gt;&lt;div&gt;=============================================================&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;我自己因為只想安裝最單純的指令列Linux, 所以選擇將NetworkManager關掉:&lt;/div&gt;&lt;div&gt;&lt;div&gt;# disable NetworkManager&lt;/div&gt;&lt;div&gt;sudo systemctl disable NetworkManager.service&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;到這裡就可以安裝nsd了。&lt;/div&gt;&lt;div&gt;sudo apt update&lt;/div&gt;&lt;div&gt;sudo apt upgrade&lt;/div&gt;&lt;div&gt;sudo apt install nsd&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;裝完, 可以設定nsd, 主要有2個設定檔:&lt;/div&gt;&lt;div&gt;sudo nano /etc/nsd/nsd.conf&lt;/div&gt;&lt;div&gt;sudo nano /var/lib/nsd/example.com.zone&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;設定檔如果都設定正確了, 可以啓動:&lt;/div&gt;&lt;div&gt;sudo systemctl start nsd&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;可以設定在開機時, 就啓動它:&lt;/div&gt;&lt;div&gt;sudo systemctl enable nsd&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;之後就可以使用dig, nslookup或者網路工具(如 dns checker)來檢查設定的對不對。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;平時可以檢查nsd有沒有跑起來:&lt;/div&gt;&lt;div&gt;&amp;nbsp;systemctl list-units --type=service --state=running&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;**********************************************************************&lt;/div&gt;&lt;div&gt;*&amp;nbsp; 錯誤訊息:&amp;nbsp; Cannot open /var/log/nsd.log for appending (Read-only file system)&lt;/div&gt;&lt;div&gt;**********************************************************************&lt;/div&gt;&lt;div&gt;我去問了Copilot, 它列了一些可能的問題點, 其中我覺得有用的是, 它說systemd sandbox 限制, 可以查看NSD 的 systemd 服務檔案，看它是否限制了寫入 /var/log？&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;特別注意以下幾個欄位是否啟用：&lt;/div&gt;&lt;div&gt;- ProtectSystem=full 或 strict：可能導致 /var/log 無法寫入&lt;/div&gt;&lt;div&gt;- ReadOnlyPaths=/var/log：明確將 /var/log 設為唯讀&lt;/div&gt;&lt;div&gt;- ReadWritePaths=：若有設定，應包含 /var/log 或你指定的 log 路徑&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;我下指令 sudo nano /lib/systemd/system/nsd.service 指令查看, 發現可疑的設定處:&lt;/div&gt;&lt;div&gt;&lt;div&gt;ProtectSystem=strict&lt;/div&gt;&lt;div&gt;ReadWritePaths=/var/lib/nsd /etc/nsd /run&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;所以問題明顯地出在這裡了, 我做了修改:&lt;/div&gt;&lt;div&gt;ReadWritePaths=/var/lib/nsd /etc/nsd /run /var/log&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;存檔後, 下指令:&amp;nbsp;&lt;/div&gt;&lt;div&gt;sudo systemctl daemon-reexec&lt;/div&gt;&lt;div&gt;sudo systemctl restart nsd&lt;/div&gt;&lt;div&gt;sudo systemctl status nsd&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;$ sudo systemctl status nsd&lt;/div&gt;&lt;div&gt;● nsd.service - Name Server Daemon&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;Loaded: loaded (/usr/lib/systemd/system/nsd.service; enabled; preset: enabled)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;Active: active (running) since Wed 2025-07-09 09:13:32 UTC; 57min ago&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Docs: man:nsd(8)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;Main PID: 4340 (nsd: xfrd)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; Tasks: 3 (limit: 1002)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;Memory: 38.1M (peak: 38.3M)&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; CPU: 131ms&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;CGroup: /system.slice/nsd.service&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;├─4340 /usr/sbin/nsd -d -P&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;├─4342 /usr/sbin/nsd -d -P&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;└─4343 /usr/sbin/nsd -d -P&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Jul 09 09:13:32 nserver systemd[1]: Starting nsd.service - Name Server Daemon...&lt;/div&gt;&lt;div&gt;Jul 09 09:13:32 nserver systemd[1]: Started nsd.service - Name Server Daemon.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;果然, 錯誤訊息不見了。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;也可以用&lt;/div&gt;&lt;div&gt;journalctl -u nsd&lt;/div&gt;&lt;div&gt;來查看log訊息。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/8440463070217633650/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/8440463070217633650?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/8440463070217633650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/8440463070217633650'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2025/07/ubuntu-2404nsdauthoritative-dns-server.html' title='在Ubuntu 24.04上使用nsd安裝一台Authoritative DNS Server'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-5251355255519207455</id><published>2025-04-11T14:47:00.003+08:00</published><updated>2025-04-11T14:51:44.427+08:00</updated><title type='text'>Khadas VIM3 開發板Android的源碼編譯好後，如何燒錄?</title><content type='html'>&lt;p&gt;&amp;nbsp;在Khadas community找到的文章&lt;a href=&quot;https://forum.khadas.com/t/vim3-vim3l-aosp-android-14-0-upside-down-cake/21192&quot; target=&quot;_blank&quot;&gt;vim3-vim3l-aosp-android-14-0-upside-down-cake&lt;/a&gt;, 以下試著照做看看！&lt;/p&gt;&lt;p&gt;1﹒ 先跳過自行編譯源碼的部份，直接下載他們已經編好的影像檔&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;2﹒ 準備燒錄工具 pyamlboot&lt;/p&gt;&lt;p&gt;直接在命令列，下以下指令： &lt;br /&gt;&lt;/p&gt;&lt;pre class=&quot;codeblock-buttons&quot;&gt;&lt;code class=&quot;hljs language-undefined&quot; data-highlighted=&quot;yes&quot;&gt;pip3 install pyamlboot&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;結果出現錯誤訊息：error: externally-managed-environment，找了一下，有一文&lt;a href=&quot;https://stackoverflow.com/questions/75608323/how-do-i-solve-error-externally-managed-environment-every-time-i-use-pip-3&quot; target=&quot;_blank&quot;&gt;stackoverflow&lt;/a&gt;，很多人在討論並提出很多解法。我採用python venv的做法:&lt;/p&gt;&lt;p&gt;(1)&amp;nbsp; 先安裝venv: sudo apt install python3-venv&lt;/p&gt;&lt;p&gt;(2)&amp;nbsp; 建立一個venv: python3 -m venv .venv&lt;/p&gt;&lt;p&gt;(3) 啟動這個venv:&amp;nbsp; source .venv/bin/activate&lt;/p&gt;&lt;p&gt;(4) 在這個venv下安裝pyamlboot: (.venv) $ pip3 install pyamlboot&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;3. 讓VIM3開發板進入USB upgrade mode&lt;/p&gt;&lt;p&gt;(1) 供電&lt;/p&gt;&lt;p&gt;(2) 在2秒內，快速按F鍵3次，放開&lt;/p&gt;&lt;p&gt;(3) 藍色LED燈會閃3秒，然後熄滅, 這樣就進入 USB upgrade mode&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/5251355255519207455/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/5251355255519207455?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/5251355255519207455'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/5251355255519207455'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2025/04/khadas-vim3-android.html' title='Khadas VIM3 開發板Android的源碼編譯好後，如何燒錄?'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-1889730325077222667</id><published>2025-03-21T16:56:00.003+08:00</published><updated>2025-03-21T17:38:15.863+08:00</updated><title type='text'>Khadas VIM3 開發板Android的源碼編譯</title><content type='html'>&lt;p&gt;&amp;nbsp;續上篇, 完成源碼的下載後, 如何編譯呢?&lt;/p&gt;&lt;p&gt;首先要把相關的工具準備好, 官網有文章&lt;a href=&quot;https://docs.khadas.com/products/sbc/vim3/development/android/install-toolchains&quot; target=&quot;_blank&quot;&gt;install-toolchains&lt;/a&gt;說明, 有2個方法, 第一個方法是直接在ubuntu下一些指令, 另一個方法是利用Docker, 把預先弄好的Docker Image抓下來, 再跑起來, 就可以在裡面進行編譯Android源碼的動作。&lt;/p&gt;&lt;p&gt;因為我之前在電腦上已經裝過編譯Orange Pi的Android 12的工具, 不想2個開發板的環境混在一起, 加上想試一下Docker怎麼使用, 所以選擇了第二個方法。&lt;/p&gt;&lt;p&gt;基本上依文件的指令下就可以, 但裝Docker的部份, 若要取得最新的版本, 可能要去查一下Docker的文件。接著取得&lt;span style=&quot;background-color: #fbfaf9; color: #333377; font-family: Consolas, &amp;quot;Andale Mono WT&amp;quot;, &amp;quot;Andale Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, &amp;quot;Nimbus Mono L&amp;quot;, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 17.6px;&quot;&gt;wesion&lt;/span&gt;&lt;span class=&quot;sy0&quot; style=&quot;background-color: #fbfaf9; color: #66cc66; font-family: Consolas, &amp;quot;Andale Mono WT&amp;quot;, &amp;quot;Andale Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, &amp;quot;Nimbus Mono L&amp;quot;, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 17.6px;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;background-color: #fbfaf9; color: #333377; font-family: Consolas, &amp;quot;Andale Mono WT&amp;quot;, &amp;quot;Andale Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, &amp;quot;Nimbus Mono L&amp;quot;, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 17.6px;&quot;&gt;khadas_android:v0.6&lt;/span&gt;這個Image, 然後把它跑起來。&lt;/p&gt;&lt;p&gt;文件上寫下這個指令:&lt;/p&gt;&lt;pre class=&quot;code shell&quot; style=&quot;background-color: #fbfaf9; border-radius: 6px; border: 1px solid rgb(204, 204, 204); color: #333333; direction: ltr; font-family: Consolas, &amp;quot;Andale Mono WT&amp;quot;, &amp;quot;Andale Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, &amp;quot;Nimbus Mono L&amp;quot;, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 17.6px; margin-bottom: 1.4em; margin-top: 0px; max-height: 400px; overflow-wrap: normal; overflow: auto; padding: 0.7em 1em;&quot;&gt;&lt;span class=&quot;sc66&quot; style=&quot;color: #333377;&quot;&gt;sudo docker run --privileged -i -t -v &lt;span class=&quot;sy0&quot; style=&quot;color: #66cc66;&quot;&gt;/&lt;/span&gt;home&lt;span class=&quot;sy0&quot; style=&quot;color: #66cc66;&quot;&gt;/&lt;/span&gt;you_name:&lt;span class=&quot;sy0&quot; style=&quot;color: #66cc66;&quot;&gt;/&lt;/span&gt;home&lt;span class=&quot;sy0&quot; style=&quot;color: #66cc66;&quot;&gt;/&lt;/span&gt;android wesion&lt;span class=&quot;sy0&quot; style=&quot;color: #66cc66;&quot;&gt;/&lt;/span&gt;khadas_android:v0.6 bash&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;全部照抄就可以, 但是/home/you_name:/home/android這個部份要改一下, 前面我們下載Android源碼時, 文件有叫我們建一個工作目錄, 我使用/home/ops/work這個目錄名稱, 所以整個Android源碼的程式都放置在這個目錄下。為了讓Docker跑起來後, 可以存取到Android源碼目錄, 指令的這個部份我改為/home/ops/work:/work (用來取代前面提到的/home/you_name:/home/android)。改成這樣, 下指令, 會看到命令提示字元變成類似:&lt;/p&gt;&lt;p&gt;root@3458795s8df812:/work#&lt;/p&gt;&lt;p&gt;這樣就進去Docker這個環境了, 如果要離開, 只要下exit指令就可, 同樣命令提示字元會回到原來的樣子。在這個環境裡下df指令, 就可以看到可以存取的目錄有那些, 我們只要關心是不是有/work這個目錄就可以了。有的話, cd進去, 然後照著官網的&lt;a href=&quot;https://docs.khadas.com/products/sbc/vim3/development/android/build-android&quot; target=&quot;_blank&quot;&gt;build-android&lt;/a&gt;文件做就可以。&lt;/p&gt;&lt;p&gt;以編譯Android 9 64位元為例:&lt;/p&gt;&lt;p&gt;分為2個步驟:&lt;/p&gt;&lt;p&gt;1. 先編譯bootloader&lt;/p&gt;&lt;pre class=&quot;code shell&quot; style=&quot;background-color: #fbfaf9; border-radius: 6px; border: 1px solid rgb(204, 204, 204); color: #333333; direction: ltr; font-family: Consolas, &amp;quot;Andale Mono WT&amp;quot;, &amp;quot;Andale Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, &amp;quot;Nimbus Mono L&amp;quot;, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 17.6px; margin-bottom: 1.4em; margin-top: 0px; max-height: 400px; overflow-wrap: normal; overflow: auto; padding: 0.7em 1em;&quot;&gt;&lt;span class=&quot;sc66&quot; style=&quot;color: #333377;&quot;&gt;&lt;span class=&quot;co66&quot; style=&quot;color: #6666cc;&quot;&gt;$ &lt;/span&gt;cd /home&lt;/span&gt;
&lt;span class=&quot;sc66&quot; style=&quot;color: #333377;&quot;&gt;&lt;span class=&quot;co66&quot; style=&quot;color: #6666cc;&quot;&gt;$ &lt;/span&gt;cd bootloader&lt;span class=&quot;sy0&quot; style=&quot;color: #66cc66;&quot;&gt;/&lt;/span&gt;uboot&lt;/span&gt;
&lt;span class=&quot;sc66&quot; style=&quot;color: #333377;&quot;&gt;&lt;span class=&quot;co66&quot; style=&quot;color: #6666cc;&quot;&gt;$ &lt;/span&gt;.&lt;span class=&quot;sy0&quot; style=&quot;color: #66cc66;&quot;&gt;/&lt;/span&gt;mk TARGET&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;注意, 這裡的TARGET, 如果開發板是VIM3, 就要改成kvim3。如果是VIM3L的開發板, 就改成kvim3l。因為官網的文件把這段話放在文件的最下面, 一開始, 我還真的傻傻的照打TARGET, 當然出來一堆錯誤訊息。正常的話, 最後應該會看到類似如下:&lt;/p&gt;&lt;p&gt;Amlogic img found, use new FIP structure!&lt;/p&gt;&lt;p&gt;Creating &quot;fip/_tmp/fip.bin&quot;&lt;/p&gt;&lt;p&gt;Firmware Image Package ToC:&lt;/p&gt;&lt;p&gt;---------------------------&lt;/p&gt;&lt;p&gt;- SCP Firmware BL3-0: offset=0x4000, size=0xD400&lt;/p&gt;&lt;p&gt;- EL3 Runtime Firmware BL3-1: offset=0x14000, size=0x2F150&lt;/p&gt;&lt;p&gt;- Non-Trusted Firmware BL3-3: offset=0x44000, size=0x149570&lt;/p&gt;&lt;p&gt;---------------------------&lt;/p&gt;&lt;p&gt;Bootloader build done!&lt;/p&gt;&lt;div&gt;2. 編譯Android本身:&lt;/div&gt;&lt;div&gt;&lt;pre class=&quot;code shell&quot; style=&quot;background-color: #fbfaf9; border-radius: 6px; border: 1px solid rgb(204, 204, 204); color: #333333; direction: ltr; font-family: Consolas, &amp;quot;Andale Mono WT&amp;quot;, &amp;quot;Andale Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, &amp;quot;Nimbus Mono L&amp;quot;, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 17.6px; margin-bottom: 1.4em; margin-top: 0px; max-height: 400px; overflow-wrap: normal; overflow: auto; padding: 0.7em 1em;&quot;&gt;&lt;span class=&quot;sc66&quot; style=&quot;color: #333377;&quot;&gt;&lt;span class=&quot;co66&quot; style=&quot;color: #6666cc;&quot;&gt;$ &lt;/span&gt;cd /home&lt;/span&gt;
&lt;span class=&quot;sc66&quot; style=&quot;color: #333377;&quot;&gt;&lt;span class=&quot;co66&quot; style=&quot;color: #6666cc;&quot;&gt;$ &lt;/span&gt;source build&lt;span class=&quot;sy0&quot; style=&quot;color: #66cc66;&quot;&gt;/&lt;/span&gt;envsetup.sh&lt;/span&gt;
&lt;span class=&quot;sc66&quot; style=&quot;color: #333377;&quot;&gt;&lt;span class=&quot;co66&quot; style=&quot;color: #6666cc;&quot;&gt;$ &lt;/span&gt;lunch TARGET_LUNCH&lt;/span&gt;
&lt;span class=&quot;sc66&quot; style=&quot;color: #333377;&quot;&gt;&lt;span class=&quot;co66&quot; style=&quot;color: #6666cc;&quot;&gt;$ &lt;/span&gt;make -jN otapackage&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同樣, 這裡的TARGET_LUNCH也要依開發板不同而改填不一樣的值, 對於VIM3開發板來說, 要改成kvim3-userdebug。還有-jN要改成-j8或者-j16之類的, 數字的大小, 基本上填你的主機的CPU核心數就可以。例如, 8核的CPU, 那就填-j8。&lt;/p&gt;&lt;p&gt;很不幸地, 我的第一次編譯嘗試失敗了。&lt;/p&gt;&lt;p&gt;出現了一堆錯誤訊息, 依照訊息的文字說明, 試著google看看, 結果找到&lt;a href=&quot;https://forum.khadas.com/t/vim3-build-android-android-9-0-64-bit-failed/19285/15&quot; target=&quot;_blank&quot;&gt;vim3-build-android-android-9-0-64-bit-failed&lt;/a&gt;這篇, 這是khadas社區的討論區, 可以拉到幾乎最下面的地方, 結果是編譯的這台主機本身的Linux核心版本也會影響Android編譯的成敗。簡單說, 解方就是要去修改art/runtime/mem_map.cc這個檔案。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfoYKaXIttQE2iFuGsrWb4Em9K1tsTxnS29ArHBvVOwUBI9wqpe_0BO32fTaiP28PJAAnQNLqcAvp7Axnb3-zx33g1aE4o0xYltj2qdLgXTXkQDFTfs678YkmX97e4MfI9g0VEc-ob8Ya9UnG2bIZStxyPE5QukSl95J43AvPfcNazG7bH89SFeYJ47gU/s1491/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-21%20173646.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;599&quot; data-original-width=&quot;1491&quot; height=&quot;258&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfoYKaXIttQE2iFuGsrWb4Em9K1tsTxnS29ArHBvVOwUBI9wqpe_0BO32fTaiP28PJAAnQNLqcAvp7Axnb3-zx33g1aE4o0xYltj2qdLgXTXkQDFTfs678YkmX97e4MfI9g0VEc-ob8Ya9UnG2bIZStxyPE5QukSl95J43AvPfcNazG7bH89SFeYJ47gU/w640-h258/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-21%20173646.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;照這個文件去修改後, 再重新編譯, 就成功了。&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/1889730325077222667/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/1889730325077222667?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/1889730325077222667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/1889730325077222667'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2025/03/khadas-vim3-android_21.html' title='Khadas VIM3 開發板Android的源碼編譯'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfoYKaXIttQE2iFuGsrWb4Em9K1tsTxnS29ArHBvVOwUBI9wqpe_0BO32fTaiP28PJAAnQNLqcAvp7Axnb3-zx33g1aE4o0xYltj2qdLgXTXkQDFTfs678YkmX97e4MfI9g0VEc-ob8Ya9UnG2bIZStxyPE5QukSl95J43AvPfcNazG7bH89SFeYJ47gU/s72-w640-h258-c/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-21%20173646.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-484023729042473088</id><published>2025-03-13T14:23:00.003+08:00</published><updated>2025-03-21T16:09:11.953+08:00</updated><title type='text'>Khadas VIM3 開發板的Android源碼下載</title><content type='html'>&lt;p&gt;&amp;nbsp;最近在學習Khadas VIM3這個開發板, 特別是跑Android, 第一個問題就是要先下載源碼。官網有文件&lt;a href=&quot;https://docs.khadas.com/products/sbc/vim3/development/android/download-android-source-code&quot; target=&quot;_blank&quot;&gt;download-android-source-code&lt;/a&gt;說明。以下記錄依文件操作所碰到的問題和思考如何解決, 但可能我的想法也不見得是最好的!&lt;/p&gt;&lt;p&gt;1. 先安裝git-lfs工具&lt;/p&gt;&lt;p&gt;查了一下, git-lfs是git的擴充套件, 針對大型檔案儲存對git造成的問題提供解法, 主要是大型檔案就放在雲端, 本地端就放指標就好。看了git-lfs官網說明, 建議要升到3.6.1版本。Khadas的文件仍叫我們安裝2.3.4的版本。如果要試安裝3.6.1版, 可以使用以下網址連結。&lt;/p&gt;&lt;p&gt;https://github.com/git-lfs/git-lfs/releases/download/v3.6.1/git-lfs-linux-amd64-v3.6.1.tar.gz&lt;/p&gt;&lt;p&gt;下載並解壓縮, 下 sudo ./install.sh 指令, 會出現錯誤訊息, 就下git init指令, 再重下 sudo ./install.sh 就不會有錯誤訊息了。&lt;/p&gt;&lt;p&gt;2. 建立工作目錄, 並下載manifest, 為什麼要下載這個檔案呢? 我問了ChatGPT, 他提到在同步特定Android設備的源碼時, 有些部份是特定廠商的Git Repo(也就是該設備特有的檔案物件), 不同的設備使用不同的manifest檔案來區別要同步的源碼。Khadas VIM3維護了3個不同的Android版本, 我先試用主要維護版本Android 9 64位元版。&lt;/p&gt;&lt;p&gt;下以下指令:&lt;/p&gt;&lt;pre class=&quot;code shell&quot; style=&quot;background-color: #fbfaf9; border-radius: 6px; border: 1px solid rgb(204, 204, 204); color: #333333; direction: ltr; font-family: Consolas, &amp;quot;Andale Mono WT&amp;quot;, &amp;quot;Andale Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, &amp;quot;Nimbus Mono L&amp;quot;, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 17.6px; margin-bottom: 1.4em; margin-top: 0px; max-height: 400px; overflow-wrap: normal; overflow: auto; padding: 0.7em 1em;&quot;&gt;&lt;span class=&quot;sc66&quot; style=&quot;color: #333377;&quot;&gt;$ repo init -u https:&lt;span class=&quot;sy0&quot; style=&quot;color: #66cc66;&quot;&gt;//&lt;/span&gt;github.com&lt;span class=&quot;sy0&quot; style=&quot;color: #66cc66;&quot;&gt;/&lt;/span&gt;khadas&lt;span class=&quot;sy0&quot; style=&quot;color: #66cc66;&quot;&gt;/&lt;/span&gt;android_manifest.git -b khadas-vim3-p-64bit&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;3. 開始同步源碼, 下 repo sync -c -j4, 這裡我才想到, 為什麼不是用git, 而是用repo呢? 同樣問ChatGPT, 他說repo是Google開發的一種git repo管理工具, 主要用於管理多個git repo的Android源碼。它是git的一個封裝工具, 簡化管理多個git repo的操作。這樣我就理解了, 主要是Android源碼太大, 分散放在不同的git repo, 所以要同步所有源碼時, 總不能每個git repo都去下同步指令吧! 像這裡一樣, 只下repo sync不是簡單多了嗎?&lt;/p&gt;&lt;p&gt;但下了這個指令後, 出現錯誤訊息 fetch-pack: unexpected disconnect while reading sideband packet, Google一下,&amp;nbsp;&lt;a href=&quot;https://stackoverflow.com/questions/66366582/github-unexpected-disconnect-while-reading-sideband-packet&quot; target=&quot;_blank&quot;&gt;stackoverflow&lt;/a&gt;有人討論相關的問題, 解法是: (在Linux環境下)&lt;/p&gt;&lt;p&gt;export GIT_TRACE_PACKET=1&lt;/p&gt;&lt;p&gt;export GIT_TRACE=1&lt;/p&gt;&lt;p&gt;export GIT_CURL_VERBOSE=1&lt;/p&gt;&lt;p&gt;確實在命令列下了這3個指令後, 再下repo sync -c -j1指令, 系統就開始同步工作, 沒有再看到錯誤訊息了。我不知道-j4會不會比-j1同步的更快, 但是查看網路頻寬, 是已經用滿了。&lt;/p&gt;&lt;p&gt;4. 下拉大型檔案。文件說還要下這個指令:&lt;/p&gt;&lt;pre class=&quot;code shell&quot; style=&quot;background-color: #fbfaf9; border-radius: 6px; border: 1px solid rgb(204, 204, 204); color: #333333; direction: ltr; font-family: Consolas, &amp;quot;Andale Mono WT&amp;quot;, &amp;quot;Andale Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, &amp;quot;Nimbus Mono L&amp;quot;, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 17.6px; margin-bottom: 1.4em; margin-top: 0px; max-height: 400px; overflow-wrap: normal; overflow: auto; padding: 0.7em 1em;&quot;&gt;&lt;span class=&quot;sc66&quot; style=&quot;color: #333377;&quot;&gt;&lt;span class=&quot;co66&quot; style=&quot;color: #6666cc;&quot;&gt;$ &lt;/span&gt;repo forall -c &#39;git lfs pull&#39;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;因為Android源碼相當大, 我上網的頻寬太小, 結果用了33小時才整個同步完。&lt;/p&gt;&lt;p&gt;*** 另外一個方法, 針對大陸國內, 文件說可以用百度雲盤, 我沒有百度帳號, 現在也沒辦法申請, 百度網頁說暫停港澳台民眾的申請。&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/484023729042473088/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/484023729042473088?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/484023729042473088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/484023729042473088'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2025/03/khadas-vim3-android.html' title='Khadas VIM3 開發板的Android源碼下載'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-4626541269513572385</id><published>2025-03-04T17:27:00.001+08:00</published><updated>2025-03-13T10:59:38.696+08:00</updated><title type='text'>Orange Pi Zero 2W開發板, 自行編譯好的Android 12映像檔, 如何燒到SD卡, 才能成功開機?</title><content type='html'>&lt;p&gt;&amp;nbsp;Orange Pi官方網站, 可以找到Orange Pi Zero 2W的使用手冊, 一個370頁的PDF檔案, 其中有一個章節提到如何編譯Android 12的原始檔, 如下圖:&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBiV-mTGO6Ck3_Fhdu1QnnfkZ0ohf0o5R1pWkPWlVy5iIOg2KOICklhsvrvrYizJRUH80T084hWoG_JPi9dXj3MMBNA0_1bLUcofFYq6wkhZf_phugpLtCWJYEez6OaF1v4kQd9aEko8IoGRh6jUDvyJMZlCHWycAg7J8DriqQcsqGLYgfpiIs3_jxPv8/s862/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-04%20132402.jpg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;385&quot; data-original-width=&quot;862&quot; height=&quot;286&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBiV-mTGO6Ck3_Fhdu1QnnfkZ0ohf0o5R1pWkPWlVy5iIOg2KOICklhsvrvrYizJRUH80T084hWoG_JPi9dXj3MMBNA0_1bLUcofFYq6wkhZf_phugpLtCWJYEez6OaF1v4kQd9aEko8IoGRh6jUDvyJMZlCHWycAg7J8DriqQcsqGLYgfpiIs3_jxPv8/w640-h286/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-04%20132402.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;第一步是下載原始檔, 由官網給定的Google Drive:&amp;nbsp;&lt;a href=&quot;https://drive.google.com/drive/folders/1TRHmKWy_tZoZ_1LySJAfJvfXvZ6zbNIn&quot; target=&quot;_blank&quot;&gt;H618_Android12_Source&lt;/a&gt;, 將原始檔下載下來, 因為原始檔太大, 被壓縮後還要分成多個檔案。約40GB的大小, 用100mbps的網速, 也花了半小時以上的時間才完成。接下來依手冊說明操作, 先檢查MD5, 確認檔案沒有缺損問題。就可以把多個檔案合併回一個壓縮檔了。然後解壓縮成一個原始檔目錄, 再將Orange Pi Zero 2W特定的修改碼(opizero2w_android12_patches.tar.gz)解壓縮後, 複製到原始檔的目錄去。&amp;nbsp;&lt;br /&gt;&lt;p&gt;第二步是編譯原始碼, 如下圖, 手冊是說, 需要一台跑Ubuntu 22.04的電腦, 16GB以上的記憶體, 以及200GB以上的硬碟空間, CPU當然是愈快愈好。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5lVFaxWlQkcQNlAGxkBkNCiLODIWN1MZ8dbgr-5necqjHnq5MUATn9D0vEFHHbNcnk_HpYKGQMKpO7RYYBSCwrL6aX-WJutX-3S7C2arkKJWtOLfSbBTnn8N6m4N3WVf9vXQOT1rA7krZfrhARiL1iqeI77zmblfpgIbLk9VbG2pGNXOsUi4nCipfeU4/s885/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-04%20160206.jpg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;484&quot; data-original-width=&quot;885&quot; height=&quot;350&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5lVFaxWlQkcQNlAGxkBkNCiLODIWN1MZ8dbgr-5necqjHnq5MUATn9D0vEFHHbNcnk_HpYKGQMKpO7RYYBSCwrL6aX-WJutX-3S7C2arkKJWtOLfSbBTnn8N6m4N3WVf9vXQOT1rA7krZfrhARiL1iqeI77zmblfpgIbLk9VbG2pGNXOsUi4nCipfeU4/w640-h350/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-04%20160206.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;因為我之前剛裝好一台Ubuntu 24.04的電腦, 雖然版本比較新, 可能會碰到一些問題, 但還是先嘗試一下, 看可不可以。果不期然, 在安裝編譯所需的套件時, 就有兩個套件找不到無法安裝:&lt;div&gt;&lt;span class=&quot;fontstyle0&quot;&gt;lib32ncurses5-dev和&amp;nbsp;&lt;/span&gt;libncurses5。就先試著安裝libncurses6, 想可能版本有更新, 也許就可以用了。但其實後面就碰到困難, 編譯會失敗!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;如下圖, 在 make -j8 這行指令下下去之後, 就出現錯誤。&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1TGB18MWYyzR_lvl_AUZeX_njCxN73XCnBXz-XZrtjekcPzzBOvY_mhkSnUrITQVRt3j6Zd1rptkQxYYI_Snyp-1cFuGWXVnTyYhvjdF6akXtnHkfGKyk7P2OY_1RzIWpVEWCP9FdgDHL2C6e1aJYXRTHmaC6WAuTbj11rh9EMv_5YOI0f6FaLqGw624/s858/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-04%20161819.jpg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;714&quot; data-original-width=&quot;858&quot; height=&quot;532&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1TGB18MWYyzR_lvl_AUZeX_njCxN73XCnBXz-XZrtjekcPzzBOvY_mhkSnUrITQVRt3j6Zd1rptkQxYYI_Snyp-1cFuGWXVnTyYhvjdF6akXtnHkfGKyk7P2OY_1RzIWpVEWCP9FdgDHL2C6e1aJYXRTHmaC6WAuTbj11rh9EMv_5YOI0f6FaLqGw624/w640-h532/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-04%20161819.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;錯誤訊息是libncurses.so.5檔案不存在之類的, Google了一下, 發現&lt;a href=&quot;https://stackoverflow.com/questions/73464111/libncurses-so-5-library-missing-in-ubuntu-22-04-installation-for-arm64-rapsberr&quot; target=&quot;_blank&quot;&gt;libncurses-so-5-library-missing-in-ubuntu-22-04-installation-for-arm64-rapsberr&lt;/a&gt;這個討論串, 看來似乎是發問者, 最後自己找到答案, 回來留下了解法。因為他的文字說明, 沒操作過的, 一開始不太能看得懂。我解釋一下:&lt;div&gt;1. 如果是64位元的Ubuntu, 需先設定i386外國架構(foreight architecture)。&lt;/div&gt;&lt;div&gt;----&amp;gt;&amp;nbsp;$ sudo dpkg --add-architecture i386&lt;/div&gt;&lt;div&gt;2. 要修改/etc/apt/sources.list.d/ubuntu.sources這個檔案。&lt;br /&gt;&lt;div&gt;----&amp;gt; 如下圖, 在http://security.ubuntu.com/ubuntu下方的Suites:項目後面, 加入focal-security&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrBt5suH9Wz6uAFquI_AW7cScHjM8OR2-RvxnIr6G05ChXpj31Pmr3c2MUAqO7vZa6T-iAjKq472z-T5WtsedViKAFAGzydczhKSeL3wiyyfUqfpQ_UPz8sfL5gZYhcJ_YZwresRzyZDYPaZKu_VxU6YbsaakFYk1Ups7nVFdER4z0AjSJiSJxQQzniPQ/s813/Screenshot%20from%202025-03-04%2016-34-18.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;498&quot; data-original-width=&quot;813&quot; height=&quot;392&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrBt5suH9Wz6uAFquI_AW7cScHjM8OR2-RvxnIr6G05ChXpj31Pmr3c2MUAqO7vZa6T-iAjKq472z-T5WtsedViKAFAGzydczhKSeL3wiyyfUqfpQ_UPz8sfL5gZYhcJ_YZwresRzyZDYPaZKu_VxU6YbsaakFYk1Ups7nVFdER4z0AjSJiSJxQQzniPQ/w640-h392/Screenshot%20from%202025-03-04%2016-34-18.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;然後, 更新一下:&lt;div&gt;$ sudo apt update&lt;/div&gt;&lt;div&gt;就可以安裝libncurses5:i386&lt;/div&gt;&lt;div&gt;$ sudo apt install&amp;nbsp;libncurses5:i386&lt;/div&gt;&lt;div&gt;做完這些, 我再試著重新編譯Android原始檔, 結果還是有錯誤!&lt;/div&gt;&lt;div&gt;因此, 試著再裝套件&lt;/div&gt;&lt;div&gt;$ sudo apt install libncurses5&lt;/div&gt;&lt;div&gt;然後重試, 結果就編譯成功了。&lt;/div&gt;&lt;div&gt;會出現以下訊息:&lt;/div&gt;&lt;div&gt;&lt;div&gt;#### build completed successfully (01:03:13 (hh:mm:ss)) ####&lt;/div&gt;&lt;/div&gt;&lt;div&gt;表示在這台機器上編譯花了1小時3分鐘! make -j8的意思, 好像是說用8個進程來編, 那也許使用16個進程(make -j16), 可以在半小時內編完哦! 我還沒去試, 不過想來是如此。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;最後下pack, 就如手冊所說, 在longan/out目錄下會找到一個h618_android12_p2_uart0.img的映像檔。然後呢? 要怎樣才能讓這個img檔跑起來?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;首先, 試著使用balenaEtcher來燒錄到SD卡。 結果打開img檔, 就出現錯誤訊息:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXCut7tL8lB5yMnmgUOhhe8WESooM4phcFT5pqc0kh4P4x4N-fuUO69XqHQYyL-IAKDA5owkZsi0ZLjhnxuNSzFxqzBA9iK0gsxqQIP3G2aScvzn2Lr-sdbVfhUEXmYm4vfwg1ieos3P6rVmsR0OQF1vmOlDEHqTTWoJbfvBzVmLPYrZV7yAdqoG2wNcg/s802/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-04%20170309.jpg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;512&quot; data-original-width=&quot;802&quot; height=&quot;408&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXCut7tL8lB5yMnmgUOhhe8WESooM4phcFT5pqc0kh4P4x4N-fuUO69XqHQYyL-IAKDA5owkZsi0ZLjhnxuNSzFxqzBA9iK0gsxqQIP3G2aScvzn2Lr-sdbVfhUEXmYm4vfwg1ieos3P6rVmsR0OQF1vmOlDEHqTTWoJbfvBzVmLPYrZV7yAdqoG2wNcg/w640-h408/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-04%20170309.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;不信, 硬燒下去, 結果就是無法開機。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;接著, 試著用PhoenixCard V4.2.8這個燒錄軟體來燒。選啟動卡, 燒卡。&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZgJVGMI4jdjheUCPZON9mYtXkoavZfZv-dWo9ZZRwMCLO_FAQJFI9Qo6vjQjHFAp9aXEBiOEmPCUqzmJ3uZiJYZ_UenHmck-9PzkWpmczCAgPH_qA0R3bfFbyWmk3-pKO_YKC8B33ikrCQjgdhYB7xdJlCkMjpbfEw71qYZIFRo9kfHG406TDgAQzJZ0/s910/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-04%20171024.jpg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;715&quot; data-original-width=&quot;910&quot; height=&quot;502&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZgJVGMI4jdjheUCPZON9mYtXkoavZfZv-dWo9ZZRwMCLO_FAQJFI9Qo6vjQjHFAp9aXEBiOEmPCUqzmJ3uZiJYZ_UenHmck-9PzkWpmczCAgPH_qA0R3bfFbyWmk3-pKO_YKC8B33ikrCQjgdhYB7xdJlCkMjpbfEw71qYZIFRo9kfHG406TDgAQzJZ0/w640-h502/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-04%20171024.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;再開機看看, 結果:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqiANwt4QS4h8CYCO9Ho-EdnB0ax6l5QWcvmhaUAOe9VuZfzT4WiMzqk-ctVDlMb_yiE6ONM9p8moTHgmeUWLdUdbkQmey7txrF2rlCSk672KyH9w4pTio8kKXnJjwoYfjRysW_hAlLk_OnIZlq7IiNHGDbDi8802vBVMqic-eSeMMWRm_HgduQhS5rfo/s563/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-04%20171914.jpg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;135&quot; data-original-width=&quot;563&quot; height=&quot;154&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqiANwt4QS4h8CYCO9Ho-EdnB0ax6l5QWcvmhaUAOe9VuZfzT4WiMzqk-ctVDlMb_yiE6ONM9p8moTHgmeUWLdUdbkQmey7txrF2rlCSk672KyH9w4pTio8kKXnJjwoYfjRysW_hAlLk_OnIZlq7IiNHGDbDi8802vBVMqic-eSeMMWRm_HgduQhS5rfo/w640-h154/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-04%20171914.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;又失敗了!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;然後找到這個貼文:&amp;nbsp;&lt;a href=&quot;http://www.orangepi.cn/orangepibbscn/forum.php?mod=viewthread&amp;amp;tid=26&quot; target=&quot;_blank&quot;&gt;OPI-PC OPI-2 OPI-PLUS安卓镜像烧写教程&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7ufLive3oUX-Rjyz7COLKk2IGVwMluH5GKTqWz1niaOOGPIEuBKl0Ys1FMiHtNbn-IzDAT-WP1loVEN6niJCDCuzXiD0fDoA6n2p0eBs7BmA6ltJjbgsao3_xSGLGM4eQdLyEpnq6XVbOSEC2OWIx3HANe8Q4-xXkfH_u_GBY6mUhX3cLm8ll9nNAdDI/s1271/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-04%20172158.jpg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;646&quot; data-original-width=&quot;1271&quot; height=&quot;326&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7ufLive3oUX-Rjyz7COLKk2IGVwMluH5GKTqWz1niaOOGPIEuBKl0Ys1FMiHtNbn-IzDAT-WP1loVEN6niJCDCuzXiD0fDoA6n2p0eBs7BmA6ltJjbgsao3_xSGLGM4eQdLyEpnq6XVbOSEC2OWIx3HANe8Q4-xXkfH_u_GBY6mUhX3cLm8ll9nNAdDI/w640-h326/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-04%20172158.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;看了一下, 不一樣的地方只有在燒錄前要把SD卡, 使用SD Card Formatter這個軟體格式化。接著還是用PhoenixCard來燒錄。原本不太相信, 姑且試之, 沒想到, 就成功了。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/4626541269513572385/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/4626541269513572385?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/4626541269513572385'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/4626541269513572385'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2025/03/orange-pi-zero-2w-android-12-sd.html' title='Orange Pi Zero 2W開發板, 自行編譯好的Android 12映像檔, 如何燒到SD卡, 才能成功開機?'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBiV-mTGO6Ck3_Fhdu1QnnfkZ0ohf0o5R1pWkPWlVy5iIOg2KOICklhsvrvrYizJRUH80T084hWoG_JPi9dXj3MMBNA0_1bLUcofFYq6wkhZf_phugpLtCWJYEez6OaF1v4kQd9aEko8IoGRh6jUDvyJMZlCHWycAg7J8DriqQcsqGLYgfpiIs3_jxPv8/s72-w640-h286-c/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-03-04%20132402.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-8182780218208345917</id><published>2025-02-24T09:03:00.007+08:00</published><updated>2025-02-25T14:16:08.362+08:00</updated><title type='text'>QNAP TR-004, TR-002使用感想</title><content type='html'>&lt;p&gt;&amp;nbsp;最近有儲存空間的需求, 買了QNAP的TR-004和TR-002, 這不是NAS, 是DAS, 簡單的說可以看成是有硬體RAID功能的&quot;大&quot;型隨身碟或外接硬碟。&lt;/p&gt;&lt;p&gt;因為重視的是資料保存安全, 所以使用RAID 1或5, 這樣硬碟若有一顆故障, 只要更換就可以。這種外接RAID都是熱插拔, 也不會中斷系統的使用。試過硬碟有問題時, 機器會發出異常聲響, 燈號會閃爍。只是若機器放在機房, 可能不會聽到! 監控軟體就很重要, 管理員從監控軟體可以看到硬碟狀況, 或者主動寄電子郵件通知, 就比較可以掌握實際情況。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5WF3XMUkjMMTaZBam9as3jRuyBzs_NOUsuBOzCd9jA4a48lNeii-SK70532OYbPdeqd9R4o8T3QfFzwbl2YkIUaeMTd_QY9SPs1c7w9FT1vEAt2L2bt4e2yi5g1rDLaGl9-gwNO6aR-YxdSeou4pLqarhDelioSageN0WccsPK7Dl2xvc2m-Y3YnlbGU/s1077/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-02-24%20084010.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;686&quot; data-original-width=&quot;1077&quot; height=&quot;408&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5WF3XMUkjMMTaZBam9as3jRuyBzs_NOUsuBOzCd9jA4a48lNeii-SK70532OYbPdeqd9R4o8T3QfFzwbl2YkIUaeMTd_QY9SPs1c7w9FT1vEAt2L2bt4e2yi5g1rDLaGl9-gwNO6aR-YxdSeou4pLqarhDelioSageN0WccsPK7Dl2xvc2m-Y3YnlbGU/w640-h408/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-02-24%20084010.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;QNAP External RAID Manager可以由官網下載使用, 用來查看機器和個別硬碟的情況, 其實是簡單明瞭, 够用了。但可惜的是, 這個官方提供的工具只有Windows和Mac版本, 沒有Linux版本!&amp;nbsp;&lt;/p&gt;&lt;p&gt;針對Linux, 我在網路上找了一下, 發現:&amp;nbsp;&lt;a href=&quot;https://www.reddit.com/r/qnap/comments/14tciaw/tr004_drive_health_status_linux/&quot; target=&quot;_blank&quot;&gt;Tr-004 Drive Health Status Linux&lt;/a&gt;&amp;nbsp;這討論文, 有人提到可以下這個指令:&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;span style=&quot;background-color: #f8f8f8; color: #333d42; font-family: &amp;quot;Noto Mono&amp;quot;, Menlo, Monaco, Consolas, monospace; font-size: 12.6px; white-space-collapse: preserve;&quot;&gt;smartctl -d jmb39x-q,0 -a /dev/sdb1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;試了一下是可以用的, 在ubuntu要有安裝smartmontools套件:&lt;/p&gt;&lt;p&gt;sudo apt install smartmontools&amp;nbsp;&lt;/p&gt;&lt;p&gt;而因為TR-004是使用JMicron晶片, 所以要下-d jmb39x-q參數, 後面加上第幾顆硬碟的參數(0代表第一顆, 1代表第二顆, ...)&lt;/p&gt;&lt;p&gt;指令執行結果, 如下:&lt;/p&gt;&lt;p&gt;$ sudo smartctl -d jmb39x-q,0 -H /dev/sda1&lt;/p&gt;&lt;p&gt;smartctl 7.4 2023-08-01 r5530 [x86_64-linux-6.8.0-53-generic] (local build)&lt;/p&gt;&lt;p&gt;Copyright (C) 2002-23, Bruce Allen, Christian Franke, www.smartmontools.org&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;=== START OF READ SMART DATA SECTION ===&lt;/p&gt;&lt;p&gt;SMART Status not supported: NO DATA ATA commands not implemented [JMB39x]&lt;/p&gt;&lt;p&gt;SMART overall-health self-assessment test result: &lt;span style=&quot;color: #2b00fe;&quot;&gt;PASSED&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Warning: This result is based on an Attribute check.&lt;/p&gt;&lt;div&gt;* 但因為TR-002使用不同的晶片, 要下何參數, 待查!&lt;/div&gt;&lt;div&gt;=&amp;gt; 有看到別人是這樣下指令:&lt;/div&gt;&lt;div&gt;$ sudo smartctl -d sat,auto -H /dev/sda&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;smartctl 7.4 2023-08-01 r5530 [x86_64-linux-6.8.0-53-generic] (local build)&lt;/div&gt;&lt;div&gt;Copyright (C) 2002-23, Bruce Allen, Christian Franke, www.smartmontools.org&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;=== START OF READ SMART DATA SECTION ===&lt;/div&gt;&lt;div&gt;SMART Health Status: OK&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;有得到簡單直接的回答, 不過, 這看起來是針對整個RAID, 不是針對個別硬碟。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;那麼效能呢? 原本查的資訊顯示TR-004是USB 3.0的界面, 想說那也有5Gbps, 結果一測, 不如預期! 如下圖:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieMZ5HaxnY9rSe_KHyr8W2lUIfSrw15PYu3da6E-W9AV8DjqhqtmJXPbRzr5c1e-xjHHpcOAlb2ZVTvRoxzs-3cTb2hrlul78fqnwb3_B5VsMzRZI8mYwexXpDYL97QPUUTTQiZEMTjhGG-DZ9SjHhfx59VqtCJqA1qMVlbKcL0Lr8_ue6MBQYPwdjD_Y/s656/Screenshot%20from%202025-02-24%2009-13-10.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;628&quot; data-original-width=&quot;656&quot; height=&quot;612&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieMZ5HaxnY9rSe_KHyr8W2lUIfSrw15PYu3da6E-W9AV8DjqhqtmJXPbRzr5c1e-xjHHpcOAlb2ZVTvRoxzs-3cTb2hrlul78fqnwb3_B5VsMzRZI8mYwexXpDYL97QPUUTTQiZEMTjhGG-DZ9SjHhfx59VqtCJqA1qMVlbKcL0Lr8_ue6MBQYPwdjD_Y/w640-h612/Screenshot%20from%202025-02-24%2009-13-10.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;個別硬碟只支援到SATA 3Gb/s, 導致整組的效能只在240MB/s以下, 枉費我給它裝了可以跑到500+MB/s的SSD!&amp;nbsp;&lt;div&gt;相反地, TR-002的效能就好很多, 之前看的資料是支援USB 3.0 Gen 2 10Gbps, 實測結果如下:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjj62ev5WWkiRdCslJAlalro1FvZCBHW8PH0MbXFIBwtogmqYYElrkQIACe-5Pa2w13dsg878SHBRVdlKZU8_W2F9XrPLmg-5z6FNG6bctCdroKyC7Wxqy7h6gp-TAp-yFndRuQtqXWne3UiQWV2OTqYS1IIDrcVkMFeNsv119nPeuglLaqdgrSSuervB4/s656/Screenshot%20from%202025-02-24%2009-31-04.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;628&quot; data-original-width=&quot;656&quot; height=&quot;612&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjj62ev5WWkiRdCslJAlalro1FvZCBHW8PH0MbXFIBwtogmqYYElrkQIACe-5Pa2w13dsg878SHBRVdlKZU8_W2F9XrPLmg-5z6FNG6bctCdroKyC7Wxqy7h6gp-TAp-yFndRuQtqXWne3UiQWV2OTqYS1IIDrcVkMFeNsv119nPeuglLaqdgrSSuervB4/w640-h612/Screenshot%20from%202025-02-24%2009-31-04.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;讀取可以到500MB/s左右, 寫入只到340MB/s左右, 可以算是有發揮到SSD的效能了。&lt;br /&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/8182780218208345917/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/8182780218208345917?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/8182780218208345917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/8182780218208345917'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2025/02/qnap-tr-004-tr-002.html' title='QNAP TR-004, TR-002使用感想'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5WF3XMUkjMMTaZBam9as3jRuyBzs_NOUsuBOzCd9jA4a48lNeii-SK70532OYbPdeqd9R4o8T3QfFzwbl2YkIUaeMTd_QY9SPs1c7w9FT1vEAt2L2bt4e2yi5g1rDLaGl9-gwNO6aR-YxdSeou4pLqarhDelioSageN0WccsPK7Dl2xvc2m-Y3YnlbGU/s72-w640-h408-c/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-02-24%20084010.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-608813084754481942</id><published>2025-02-19T11:04:00.004+08:00</published><updated>2025-03-04T13:16:37.007+08:00</updated><title type='text'>安裝ubuntu server 24.04, 含RAID 1, GUI 紀錄</title><content type='html'>&lt;p&gt;&amp;nbsp;1. 組裝好PC後, 記得先更新主機板的firmware!&amp;nbsp; 以ASUS主機板來說, 到官網找到對應板子的BIOS下載, 會拿到一個ZIP檔, 解開後, 放到格式化為FAT32的USB隨身碟, 開機按F1或DEL進入BIOS。找到更新firmware的地方, 插入USB隨身碟, 選取新的firmware檔案。(以我的例子來說, 是TUF-GAMING-Z790-PLUS-WIFI-ASUS-1805.CAP的檔案, 更新時間並不快, 要等一下!)&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJnBbsKzk0VG8gfhNEeD9nmCPgfPvNKMAr5IMbwHKemlwxxSgzfhbNSpkiaU9yoPSpcsx68i08jdCGvykaKK4a8ngPQa6tnx_F9gzFfwiU2R26VY7-rX2_W_wanCjPVnuy5ctt4TNX-Xj5mZUHg8Dhx9jGSoB6npSVADrOTNqMski0Di0l84-cpDA640g/s1271/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-02-19%20095014.jpg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;769&quot; data-original-width=&quot;1271&quot; height=&quot;388&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJnBbsKzk0VG8gfhNEeD9nmCPgfPvNKMAr5IMbwHKemlwxxSgzfhbNSpkiaU9yoPSpcsx68i08jdCGvykaKK4a8ngPQa6tnx_F9gzFfwiU2R26VY7-rX2_W_wanCjPVnuy5ctt4TNX-Xj5mZUHg8Dhx9jGSoB6npSVADrOTNqMski0Di0l84-cpDA640g/w640-h388/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-02-19%20095014.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;2. 到ubuntu官網取得ubuntu server 24.04的ISO檔。(我拿到的是ubuntu-24.04.1-live-server-amd64.iso)&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF-y42a05SHwX4qZrFGZ3fsylB73RVOoI0QI7363bLfGVQvUItdKu6WdcFmn_VkaGo4hyphenhyphenqmsmSsBll15cSWQFzLDMyaOCd4w_nNMpDMCA5WMuTCba8fQzMuu-88QxWaW95ABf9V0GBzTW_swnygtjc1gzmKATjybiy-Gvgr1Nefjn1xDDiruRV4rnvqkM/s1400/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-02-19%20100400.jpg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;750&quot; data-original-width=&quot;1400&quot; height=&quot;342&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF-y42a05SHwX4qZrFGZ3fsylB73RVOoI0QI7363bLfGVQvUItdKu6WdcFmn_VkaGo4hyphenhyphenqmsmSsBll15cSWQFzLDMyaOCd4w_nNMpDMCA5WMuTCba8fQzMuu-88QxWaW95ABf9V0GBzTW_swnygtjc1gzmKATjybiy-Gvgr1Nefjn1xDDiruRV4rnvqkM/w640-h342/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-02-19%20100400.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;3. 將ISO檔燒錄到USB隨身碟去, 一般使用balenaEtcher。用該USB隨身碟開機, 依螢幕指示, 輸入帳號等資訊, 然後要設定二個硬碟做成RAID 1(Mirror), 這個部份可以參考以下文章:&amp;nbsp;&lt;a href=&quot;https://kifarunix.com/install-ubuntu-24-04-with-uefi-and-software-raid-1/&quot; target=&quot;_blank&quot;&gt;https://kifarunix.com/install-ubuntu-24-04-with-uefi-and-software-raid-1/&lt;/a&gt;。大致上是要先設定二個硬碟為開機碟(boot device), 此時安裝程式會在硬碟上劃分出一個約1GB大小的分區; 然後剩下的空間再分割成一個GPT分區(GPT Partition), 記得要指定為未格式化(unformatted)。然後就可以選取&lt;span style=&quot;background-color: white; color: #444444; font-family: Arial; font-size: 17px; font-weight: 700;&quot;&gt;Create Software RAID (md)&lt;/span&gt;的選項, 將分別位於2個硬碟上的分區組成一個md0的raid 1磁碟並格式化為EXT4格式且mount到/根目錄後, 就可以往後進行將ubuntu server裝到這個目錄。&lt;/p&gt;&lt;p&gt;到這裡還沒完! 重開機後, 檢查RAID 1是否正常運作。記得將開機分區, 由運作中的那個, 複製到另一個去。這樣就完成了! 之後可以拔掉任何一個硬碟, 看可不可以正常開機。&lt;/p&gt;&lt;p&gt;4. Ubuntu server沒有GUI, 所以登入都只有指令列可以使用。但有些工具, 就是需要GUI, 其實GUI還是比較人性化的。可以參考這篇文章:&amp;nbsp;&lt;a href=&quot;https://phoenixnap.com/kb/how-to-install-a-gui-on-ubuntu&quot; target=&quot;_blank&quot;&gt;https://phoenixnap.com/kb/how-to-install-a-gui-on-ubuntu&lt;/a&gt;, 大致上來說, 就是先裝一個Display Manager, 可以選擇&lt;span face=&quot;Roboto, sans-serif&quot; style=&quot;background-color: white; box-sizing: inherit; color: #22282a; font-size: 16px; font-weight: bolder;&quot;&gt;SLiM&lt;/span&gt;&lt;span face=&quot;Roboto, sans-serif&quot; style=&quot;background-color: white; color: #22282a; font-size: 16px;&quot;&gt;&amp;nbsp;或&amp;nbsp;&lt;/span&gt;&lt;span face=&quot;Roboto, sans-serif&quot; style=&quot;background-color: white; box-sizing: inherit; color: #22282a; font-size: 16px; font-weight: bolder;&quot;&gt;LightDM&lt;/span&gt;&lt;span face=&quot;Roboto, sans-serif&quot; style=&quot;background-color: white; color: #22282a; font-size: 16px;&quot;&gt;.&lt;/span&gt;。該文作者選擇&lt;span face=&quot;Roboto, sans-serif&quot; style=&quot;background-color: white; box-sizing: inherit; color: #22282a; font-size: 16px; font-weight: bolder;&quot;&gt;SLiM&lt;/span&gt;&lt;span face=&quot;Roboto, sans-serif&quot; style=&quot;background-color: white; color: #22282a; font-size: 16px;&quot;&gt;&amp;nbsp;&lt;/span&gt;我選擇了&lt;span face=&quot;Roboto, sans-serif&quot; style=&quot;background-color: white; box-sizing: inherit; color: #22282a; font-size: 16px; font-weight: bolder;&quot;&gt;LightDM&lt;/span&gt;&lt;span face=&quot;Roboto, sans-serif&quot; style=&quot;background-color: white; color: #22282a; font-size: 16px;&quot;&gt;.&lt;/span&gt;,下指令安裝之:&lt;/p&gt;&lt;p&gt;sudo apt install lightdm&lt;/p&gt;&lt;p&gt;接著是重點, 安裝ubuntu桌面:&lt;/p&gt;&lt;p&gt;sudo apt intall ubuntu-desktop&lt;/p&gt;&lt;p&gt;等它裝完, 再重開機, 下指令: sudo reboot, 重開機後, 就會看到GUI的登入畫面了。&lt;/p&gt;&lt;p&gt;-------------------------------------------------------------------------&lt;/p&gt;&lt;p&gt;註: 我安裝LightDM後, 發現登入畫面和之前的不一樣, 而且每5分鐘會自動進入睡眠(suspend), 但是由系統設定-&amp;gt;Power也關不掉! 所以決定重裝, 這次不先安裝Display Manager, 而是直接安裝ubuntu桌面, 這次它直接裝完, 也沒問要用那個Display Manager! 重開後, 登入畫面就和一般Ubuntu Desktop版本的一樣, 也不會自動進入睡眠了。 2025/2/20&lt;/p&gt;&lt;p&gt;--------------------------------------------------------------------------&lt;/p&gt;&lt;p&gt;5.在重開機的過程中, 會注意到, 原本開機很快。現在卻變慢, 會卡在一個地方等很久, 如下圖。可以參考這篇帖子:&amp;nbsp;&lt;a href=&quot;https://askubuntu.com/questions/1217252/boot-process-hangs-at-systemd-networkd-wait-online&quot; target=&quot;_blank&quot;&gt;https://askubuntu.com/questions/1217252/boot-process-hangs-at-systemd-networkd-wait-online&lt;/a&gt;, 大意是說ubuntu可以使用&lt;span face=&quot;ui-monospace, &amp;quot;Cascadia Mono&amp;quot;, &amp;quot;Segoe UI Mono&amp;quot;, &amp;quot;Liberation Mono&amp;quot;, Menlo, Monaco, Consolas, monospace&quot; style=&quot;background-color: #e3e6e8; color: #0c0d0e; font-size: 13px; white-space-collapse: preserve;&quot;&gt;systemd-networkd&lt;/span&gt;或者&lt;span face=&quot;ui-monospace, &amp;quot;Cascadia Mono&amp;quot;, &amp;quot;Segoe UI Mono&amp;quot;, &amp;quot;Liberation Mono&amp;quot;, Menlo, Monaco, Consolas, monospace&quot; style=&quot;background-color: #e3e6e8; color: #0c0d0e; font-size: 13px; white-space-collapse: preserve;&quot;&gt;NetworkManager&lt;/span&gt;來管理網路, 但不能同時用。同時用的結果, 就是會有衝突, 特別是開機的時候出現等很久的狀況。這是因為我們先安裝ubuntu server, 然後又安裝桌面的關係。簡單結論, 停用其中之一, 例如:&lt;/p&gt;&lt;p&gt;systemctl disable systemd-networkd.service&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzVglO0bgFk-fsFdFEFDNMwSOihTqPQ_n53aMmjivuz7r1a3GCikFaHPTiwB6FJiPA6MluXqRcpB-tTrqTbtc-Vkp03XjNPeB4mrGnCpFwxnqHFJ3kKjFkbL_0gE4oV2jNuBGKKBslCKw8ygFU7MTLHDprU78VxUipAxob0Ud3zzTBDzJ68SWH5WWALsQ/s592/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-02-19%20105215.jpg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;377&quot; data-original-width=&quot;592&quot; height=&quot;408&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzVglO0bgFk-fsFdFEFDNMwSOihTqPQ_n53aMmjivuz7r1a3GCikFaHPTiwB6FJiPA6MluXqRcpB-tTrqTbtc-Vkp03XjNPeB4mrGnCpFwxnqHFJ3kKjFkbL_0gE4oV2jNuBGKKBslCKw8ygFU7MTLHDprU78VxUipAxob0Ud3zzTBDzJ68SWH5WWALsQ/w640-h408/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-02-19%20105215.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/608813084754481942/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/608813084754481942?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/608813084754481942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/608813084754481942'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2025/02/ubuntu-server-2404-raid-1-gui.html' title='安裝ubuntu server 24.04, 含RAID 1, GUI 紀錄'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJnBbsKzk0VG8gfhNEeD9nmCPgfPvNKMAr5IMbwHKemlwxxSgzfhbNSpkiaU9yoPSpcsx68i08jdCGvykaKK4a8ngPQa6tnx_F9gzFfwiU2R26VY7-rX2_W_wanCjPVnuy5ctt4TNX-Xj5mZUHg8Dhx9jGSoB6npSVADrOTNqMski0Di0l84-cpDA640g/s72-w640-h388-c/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202025-02-19%20095014.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-8922046544490412751</id><published>2025-01-23T08:57:00.000+08:00</published><updated>2025-01-23T08:57:33.402+08:00</updated><title type='text'>實體主機轉成虛擬機器後, 原網路卡被隱藏並佔用了之前指定的固定IP (考古文)</title><content type='html'>&lt;p&gt;&amp;nbsp;將老舊的Windows 2003實體主機, 利用VMWare Converter轉成虛擬機器後, 因原主機為固定ip; 打開虛擬機器後, 網路卡變成VMWare的虛擬網卡, 而且自動設為DHCP, 我就將它改為原來的固定ip。結果Windows 2003跑出訊息說這個ip和隱藏的Broadcom NetXtreme GigabitEthernet網卡的ip相同, 可能會造成問題, 要不要改設另一個ip?&amp;nbsp;&lt;/p&gt;&lt;p&gt;我才了解到, 原來Converter會將原來實體網路卡隱藏起來, 並給一張新的虛擬網卡, 而且預設為DHCP。這樣當我將新的虛擬網卡設成原來固定IP時, 二張網卡的IP就會相衝突。合理的解決是將那張隱藏實體網路卡移除。2012年8月的社群討論&amp;nbsp;&lt;a href=&quot;https://community.spiceworks.com/t/hidden-network-card-configurations/163055&quot; target=&quot;_blank&quot;&gt;Hidden Network Card configurations (Spiceworks Community)&lt;/a&gt;&amp;nbsp;就已經有這個問題的解法。&lt;/p&gt;&lt;p&gt;因為原文是單純文字描述解法, 我將其實際操作畫面附上, 可以更快了解其意:&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhvYoXxQiRWcpeaDpzDjDoxC3wBvqddG2V_tbgHkZ7ASCLDoIGkKFOwOwr22z6TaozQO4SeSyQ8wuIO21xkgF1gtBzhlI6HbcYKqF3m3iGofSEpWQuVNF2J4nnAGK0w0b-tx9p4dOquCzgNqsOdMPTMIo7UIyWW8XVTIwGGxJoqg6zh87ZHdUkYSQYwPT0&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;649&quot; data-original-width=&quot;865&quot; height=&quot;480&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhvYoXxQiRWcpeaDpzDjDoxC3wBvqddG2V_tbgHkZ7ASCLDoIGkKFOwOwr22z6TaozQO4SeSyQ8wuIO21xkgF1gtBzhlI6HbcYKqF3m3iGofSEpWQuVNF2J4nnAGK0w0b-tx9p4dOquCzgNqsOdMPTMIo7UIyWW8XVTIwGGxJoqg6zh87ZHdUkYSQYwPT0=w640-h480&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;大意如下:&lt;p&gt;&lt;/p&gt;&lt;p&gt;1. 打開命令提示字元視窗&lt;/p&gt;&lt;p&gt;2. 打指令: set devmgr_show_nonpresent_devices=1&lt;/p&gt;&lt;p&gt;3. 打指令: Start DEVMGMT.MSC&lt;/p&gt;&lt;p&gt;4. 出現裝置管理員, 選&#39;檢視&#39;-&amp;gt; &#39;顯示隱藏裝置&#39;; 然後展開&#39;網路介面卡&#39;, 就會看到如上圖的多張隱藏網卡, 選取要移除的, 按右鍵, 選&#39;解除安裝&#39;即可。&lt;/p&gt;&lt;p&gt;-------------------------------------------------------------------&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/8922046544490412751/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/8922046544490412751?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/8922046544490412751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/8922046544490412751'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2025/01/ip.html' title='實體主機轉成虛擬機器後, 原網路卡被隱藏並佔用了之前指定的固定IP (考古文)'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEhvYoXxQiRWcpeaDpzDjDoxC3wBvqddG2V_tbgHkZ7ASCLDoIGkKFOwOwr22z6TaozQO4SeSyQ8wuIO21xkgF1gtBzhlI6HbcYKqF3m3iGofSEpWQuVNF2J4nnAGK0w0b-tx9p4dOquCzgNqsOdMPTMIo7UIyWW8XVTIwGGxJoqg6zh87ZHdUkYSQYwPT0=s72-w640-h480-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-6647346955315143284</id><published>2024-09-13T10:43:00.008+08:00</published><updated>2024-09-13T13:53:52.764+08:00</updated><title type='text'>sendmail routing: virtusertable, mailertable, smarttable</title><content type='html'>&lt;p&gt;&amp;nbsp;公司老闆對信件的管制都會有一些要求, sendmail的routing機制, 其實都可以應付的來, 其中3個主要設定表格應該就可以處理大部份狀況: virtusertable, mailertable, smarttable, 分別討論如下。&lt;/p&gt;&lt;p&gt;1. virtusertable&lt;/p&gt;&lt;p&gt;&amp;nbsp; 這個表格原本用來做主機代管, 一台主機要host 10家公司(網域)的email, 必然會收到10個不同網域的信件, 但實際上這主機的名稱只有一個; 這時, 就用這個表格來將對應虛擬email address到實際的位址。例如:&lt;/p&gt;&lt;p&gt;sales@example.com&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; jill&lt;/p&gt;&lt;p&gt;info@book.org&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; sara@writer.com&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;2. mailertable&lt;/p&gt;&lt;p&gt;&amp;nbsp;這個表格用來決定特定收件者網域的信要用什麼協定轉寄到那台主機(或網域), 它不管寄信者是誰。所以如果你想要設定的規則是&quot;由誰寄來的都如何....&quot;, 那麼這個表格無法處理。它可以處理的是&quot;寄到某網域的信都轉到那裡...&quot;這樣的要求, 例如:&lt;/p&gt;&lt;p&gt;book.org&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; smtp:writer.com&lt;/p&gt;&lt;p&gt;這樣的設定, 會將要寄到book.org這個網域的信都轉寄到writer.com這個網域, 而且改用smtp這個協定來傳送, 現在一般都使用esmtp這個比較新的協定, 如果有比較老舊的主機無法處理新的協定, 利用這個mailertable, 也是一個方式。&lt;/p&gt;&lt;p&gt;writer.com&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;local:pat&lt;/p&gt;&lt;p&gt;這個設定可以將所有要寄到writer.com網域的信, 都轉寄給本機上的pat這個使用者。&amp;nbsp;&lt;/p&gt;&lt;p&gt;writer.net&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;esmtp:[192.168.0.1]&lt;/p&gt;&lt;p&gt;這個設定, 則是直接將要寄到writer.net網域的信, 都轉寄給192.168.0.1這台主機。前面的例子中, 指定轉寄到另一個網域時, sendmail還是要決定那個網域的郵件主機是那台, 然後還是將信傳送到那台主機。而這個決定的方法, 就取決於你的sendmail設定, 還有DNS裡MX record的設定。所以如果你想跳過那些設定, 或者讓轉寄到那台主機更明確, 這個設定法就簡單明瞭。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;3. smarttable&lt;/p&gt;&lt;p&gt;&amp;nbsp;前面都是討論有關收件者的設定, 寄件者的部份就留給這個表格了, 也就是說&quot;由誰寄來的都如何....&quot;, 這樣的要求, 就是smarttable負責處理的了。例如:&lt;/p&gt;&lt;p&gt;@reader.com&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; esmtp:[192.168.0.2]&lt;/p&gt;&lt;p&gt;這個設定可以將由reader.com這個網域寄來的信都轉寄到192.168.0.2這台主機。&lt;/p&gt;&lt;p&gt;john@reader.com&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; esmtp:[192.168.0.3]&lt;/p&gt;&lt;p&gt;這個設定則可以針對特定寄件者做轉寄的處理, john@reader.com可能是VIP, 它的來信都要特別處理, 就轉寄到特定主機去。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;** 要讓這3個表格有作用, 必須在sendmail.mc檔裡有正確的設定:&lt;/p&gt;&lt;p&gt;FEATURE(mailertable, `hash -o /etc/mail/mailertable&#39;)&lt;/p&gt;&lt;p&gt;FEATURE(virtusertable, `hash -o /etc/mail/virtusertable&#39;)&lt;/p&gt;&lt;p&gt;VIRTUSER_DOMAIN_FILE(`/etc/mail/virtuserdomains&#39;)dnl&lt;/p&gt;&lt;p&gt;FEATURE(`smarttable&#39;)dnl&lt;/p&gt;&lt;div&gt;在我的FreeBSD主機的sendmail環境, sendmail.mc設定檔是放置在/usr/local/share/sendmail/cf/cf這個目錄, 確保sendmail.mc檔中有以上設定存在。再下以下指定將其轉換成sendmail.cf檔:&lt;/div&gt;&lt;div&gt;m4 ../m4/cf.m4 sendmail.mc &amp;gt; sendmail.cf&lt;/div&gt;&lt;div&gt;然後再將sendmail.cf複製到/etc/mail目錄去, 重開sendmail就可以了。&lt;/div&gt;&lt;div&gt;在我的FreeBSD主機的sendmail環境, 重開sendmail的方法是, 到/usr/local/etc/rc.d目錄, 下以下指令:&lt;/div&gt;&lt;div&gt;./sendmail.sh restart&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;smarttable在sendmail.mc檔裡的設定很簡單, 只是FEATURE(`smarttable&#39;)dnl, 這是開啓smarttable功能的意思, 預設其表格的位置在/etc/mail/smarttable.db。所以以上討論smarttable時, 設定的內容都是存放在/etc/mail/smarttable這個文字檔。然後改完這個設定檔, 我們必須下makemap指令, 將其轉換成db檔。如下:&lt;/div&gt;&lt;div&gt;makemap hash smarttable &amp;lt; smarttable&lt;/div&gt;&lt;div&gt;沒打錯! 就是這樣的指令, 它自然會在同一個目錄下產生smarttable.db檔。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;mailertable的設定也是一樣的, 這裡展示的是較完整的寫法, 也就是明確列示出其表格存在的目錄位置和表格的編碼。同樣的, 我們在文字檔(mailertable)編修其設定, 然後下makemap指令將其改存成.db的檔案。在sendmail環境裡, 這種表格, 由文字檔編修設定, 再下makemap指令轉成db檔的, 都具有一個特性, 就是一旦轉成db檔, 就立刻生效, 不用重開sendmail。包括這裡討論的3個表格皆如此。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;virtusertable的設定也是一樣, 用FEATURE(virtusertable)來設定之, 但注意要再加上一行VIRTUSER_DOMAIN_FILE(), 否則virtusertable不會有作用!!!!!! 其用意, 應該是一個保險吧! virtuserdomains這個文字檔很簡單, 就是要加入你想設定的虛擬網域。例如:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;example.com&lt;/div&gt;&lt;div&gt;book.org&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;這樣, 之前在virtusertable裡的設定才會有效。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjAIR8RmpXj_7z86uqcnG9s5eCZy2eAoAf_XU2Iz0GTiKj6LWKw-7ktCO9lJpIEbr0OtyYH3EQ2XlMVnUsy6QBjXO2yCqp3yH-xiHpuoFGZy4SAc20thicRaaPK7VM7GIJDVIaLuX-SsKQ5HS1Le9XMFr8sKTzyFuCZ62F4FYaLVfXaUrnA7TxJJ1V7dGc&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;377&quot; data-original-width=&quot;185&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjAIR8RmpXj_7z86uqcnG9s5eCZy2eAoAf_XU2Iz0GTiKj6LWKw-7ktCO9lJpIEbr0OtyYH3EQ2XlMVnUsy6QBjXO2yCqp3yH-xiHpuoFGZy4SAc20thicRaaPK7VM7GIJDVIaLuX-SsKQ5HS1Le9XMFr8sKTzyFuCZ62F4FYaLVfXaUrnA7TxJJ1V7dGc=w158-h320&quot; width=&quot;158&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;==================&lt;/div&gt;&lt;div&gt;作用的順序 (很重要)&lt;/div&gt;&lt;div&gt;==================&lt;/div&gt;&lt;div&gt;&amp;nbsp;sendmail是這樣處理的, 先看virtusertable, mailertable然後才看smarttable, 之後是看DNS MX record。所以由誰寄來的規則會最後被套用, 寄給那個網域的規則會比較優先處理。這是什麼意思? 意思是如果你在mailertable裡設定寄到alpha網域的信都轉寄到A主機, 在smarttable裡設定由john@dell寄來的信都轉寄到B主機。那麼由john@dell寄給marry@alpha的信, 在你這台主機收到後, 會怎麼處理呢? 轉寄A主機或B主機呢?&lt;/div&gt;&lt;div&gt;答案是mailertable先作用, 所以是轉寄到A主機。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;問題來了, 公司的網域就是alpha, 老闆的要求就是所有同仁的信都要轉寄到A主機, 但是由john@dell寄來的信, 就是要轉寄到B主機, 那麼我要怎麼設定呢?&lt;/div&gt;&lt;div&gt;可能的一個解法是:&amp;nbsp;&lt;/div&gt;&lt;div&gt;mailertable都不設定, smarttable設定由john@dell寄來的信都轉寄到B主機。那麼smarttable就會生效, 沒問題。可是公司其他同仁的信, 如何轉寄到A主機呢? 那就用DNS MX record, 這台sendmail主機指定到公司內部自己的DNS主機, 其上MX record設定alpha網域的MX是A主機就可以了。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;好險! 問題解決了!&amp;nbsp;&lt;/div&gt;&lt;div&gt;沒想到, 老闆很機車, 要求john@dell寄來的信都轉寄到B主機沒錯, 但是john@dell寄給老闆(boss@alpha)的信卻要轉寄到A主機, 這時候要如何設定呢?&lt;/div&gt;&lt;div&gt;可能的一個解決法是:&lt;/div&gt;&lt;div&gt;利用virtusertable, 將boss@alpha轉成boss@beta, 然後在mailertable設定beta網域要轉寄到A主機。所以即使是由john@dell寄來的信, 只要是寄給boss@alpha的, 都會在mailertable被轉寄到A主機。但是由john@del寄給其他人的信, 仍會轉寄到B主機。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/6647346955315143284/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/6647346955315143284?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/6647346955315143284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/6647346955315143284'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2024/09/sendmail-routing-virtusertable.html' title='sendmail routing: virtusertable, mailertable, smarttable'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEjAIR8RmpXj_7z86uqcnG9s5eCZy2eAoAf_XU2Iz0GTiKj6LWKw-7ktCO9lJpIEbr0OtyYH3EQ2XlMVnUsy6QBjXO2yCqp3yH-xiHpuoFGZy4SAc20thicRaaPK7VM7GIJDVIaLuX-SsKQ5HS1Le9XMFr8sKTzyFuCZ62F4FYaLVfXaUrnA7TxJJ1V7dGc=s72-w158-h320-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-8559021615282263748</id><published>2024-05-03T11:35:00.006+08:00</published><updated>2024-05-03T11:52:05.555+08:00</updated><title type='text'>pca10059 (nRF52840 Dongle) + circuitPython + micro SD card 讀取或寫入資料</title><content type='html'>&lt;p&gt;&amp;nbsp;有些時候，我們的IoT裝置並不連網，又或者我們就是想存些資料在micro SD卡上。在nRF52840 Dongle上，實現這個要求，搭配circuitPython的情況下，只要加裝一片SD Card模組和撰寫少許程式就可以完成。&lt;/p&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhq9KPwEExQ8lilV8eL0RLddl-8uYcpdf8OHaYZQ9U1NXj4U4nI7q_PAtMrtjiCtvpxMi4EU3maBCku5WyHIBWaVxMN6_2P-kDpC7uGsu1QbB27ENf7dMQGA_wpK9fvGHMIrAISxzSJv1wYWO9htyyQQcpRYIx0PbR7mYAkP-G2yClDI96jSLKbCej3rVY/s246/%E6%88%AA%E5%9C%96%202024-05-02%20%E4%B8%8A%E5%8D%8811.17.58.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;246&quot; data-original-width=&quot;146&quot; height=&quot;246&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhq9KPwEExQ8lilV8eL0RLddl-8uYcpdf8OHaYZQ9U1NXj4U4nI7q_PAtMrtjiCtvpxMi4EU3maBCku5WyHIBWaVxMN6_2P-kDpC7uGsu1QbB27ENf7dMQGA_wpK9fvGHMIrAISxzSJv1wYWO9htyyQQcpRYIx0PbR7mYAkP-G2yClDI96jSLKbCej3rVY/s1600/%E6%88%AA%E5%9C%96%202024-05-02%20%E4%B8%8A%E5%8D%8811.17.58.png&quot; width=&quot;146&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;我使用這個模組，這應該是市面上最常見也最便宜的micro SD card模組了，大約NT$40-50.&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFUGr1fedW5iRB5PVA_Jv3Fjdm1U1tXso52PSU9Vm6NtucNTmYt9fos6djp0poeb2_qifYJRBuZLImXGAnXS-bxZZpsOyBs-jW3z7yG_-UfEjboi_ceCg7LIViSw6OT7xWG-63JkZ4bBU_0iEXu_yecme_PhUUmVAlVRCDdtFFqGiCdLFkmlMbDiZLjVQ/s548/%E6%88%AA%E5%9C%96%202024-05-02%20%E4%B8%8A%E5%8D%8811.44.21.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;265&quot; data-original-width=&quot;548&quot; height=&quot;155&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFUGr1fedW5iRB5PVA_Jv3Fjdm1U1tXso52PSU9Vm6NtucNTmYt9fos6djp0poeb2_qifYJRBuZLImXGAnXS-bxZZpsOyBs-jW3z7yG_-UfEjboi_ceCg7LIViSw6OT7xWG-63JkZ4bBU_0iEXu_yecme_PhUUmVAlVRCDdtFFqGiCdLFkmlMbDiZLjVQ/s320/%E6%88%AA%E5%9C%96%202024-05-02%20%E4%B8%8A%E5%8D%8811.44.21.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;nRF52840 Dongle就長得如上圖，硬體接線的話要使用到總共6條線，我選擇使用Dongle(以上圖來看)下方的６個接腳（由左到右分別是：1.15, 0.02, 0.29, 0.31, GND, VDO OUT):&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;micro SD card module&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;nRF52840 Dongle&lt;/div&gt;&lt;div&gt;------------------&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;----------------&lt;/div&gt;&lt;div&gt;CS&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1.15&lt;/div&gt;&lt;div&gt;MISO&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 0.02&lt;/div&gt;&lt;div&gt;MOSI&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 0.29&lt;/div&gt;&lt;div&gt;SCK&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0.31&lt;/div&gt;&lt;div&gt;GND&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;GND&lt;/div&gt;&lt;div&gt;VCC&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;VDO OUT&lt;br /&gt;&lt;p&gt;Note: 注意哦！因為我選擇使用３V的電壓，這顆micro SD card模組的1117已經被我拔掉！另外還把其中２個接點接在一起。如下圖：&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-5y7qa2AjS3MhgElec-WN-hoG5vGYGml9xC2nkCRGTgHXxwdk54HAiarsQ3gSfzJKJdG77j2GziWQ7YqXtv8X6JcCLsZP_stoxEIKl8_cJtPAOMVx78sVko5mLP-aErVXr2kXvV5Ed6sUQs5zMSRN_4N-cXVfHM21p5DAVP-LjbLh9W75ljc5NQH8esY/s544/%E6%88%AA%E5%9C%96%202024-05-03%20%E4%B8%8A%E5%8D%8810.49.12.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;544&quot; data-original-width=&quot;359&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-5y7qa2AjS3MhgElec-WN-hoG5vGYGml9xC2nkCRGTgHXxwdk54HAiarsQ3gSfzJKJdG77j2GziWQ7YqXtv8X6JcCLsZP_stoxEIKl8_cJtPAOMVx78sVko5mLP-aErVXr2kXvV5Ed6sUQs5zMSRN_4N-cXVfHM21p5DAVP-LjbLh9W75ljc5NQH8esY/s320/%E6%88%AA%E5%9C%96%202024-05-03%20%E4%B8%8A%E5%8D%8810.49.12.png&quot; width=&quot;211&quot; /&gt;&lt;/a&gt;&lt;/div&gt;這樣的話，這個模組就可以使用和nRF52840 Dongle一樣的３V電壓，如果你不想移掉1117和改線路，那就要給這個模組VCC腳位５V的電，以nRF52840 Dongle來說，可以由VBUS這個腳位來供電（但前提是，nRF52840 Dongle必須插在USB插槽上）。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;circuitPython似乎預設是支持micro SD，所以code.py的內容：&lt;/div&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;

&#39;&#39;&#39;
Mount a MicroSD Card, using SPI interface
SPI Pin mapping:
------------------------
GPIO 0.31, SCK
GPIO 0.29, MOSI
GPIO 0.02, MISO
GPIO 1.15, CS
------------------------
&#39;&#39;&#39;
import board
import busio

spi = busio.SPI(board.P0_31, board.P0_29, board.P0_02)

import os
import sdcardio
import storage

sd = sdcardio.SDCard(spi, board.P1_15)
vfs = storage.VfsFat(sd)
storage.mount(vfs, &#39;/sd&#39;)
os.listdir(&#39;/sd&#39;)

# show data.txt contents

with open(&#39;/sd/data.txt&#39;,&#39;r&#39;) as f:
    for line in f:
        print(line.strip())


# umount
# storage.umount(&#39;/sd&#39;)


&lt;/code&gt;&lt;/pre&gt;
就可以將micro SD掛到/sd這個目錄下，並讀取其中的data.txt這個檔案的內容。我以Tonny這個環境來跑看看：&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIQIvGdNyd2vpjvO4XU8dF__oTO4dLWOmrVoqyHXRJv0Bh8yXKR0jEJvj0y2G1OO9_GL0KH6eil79OxXMUHZ_i6BdMAUeLyLzq8YBJ8UKNlCSedU-XCuXZ6oBq0vT8zpmdZpkQBdReZputhSdQ6X7QUIkwOnrjb4MmCMc5GgL3LN7tVUAB1jOo9BxpKwA/s1094/%E6%88%AA%E5%9C%96%202024-05-03%20%E4%B8%8A%E5%8D%8811.10.14.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;926&quot; data-original-width=&quot;1094&quot; height=&quot;542&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIQIvGdNyd2vpjvO4XU8dF__oTO4dLWOmrVoqyHXRJv0Bh8yXKR0jEJvj0y2G1OO9_GL0KH6eil79OxXMUHZ_i6BdMAUeLyLzq8YBJ8UKNlCSedU-XCuXZ6oBq0vT8zpmdZpkQBdReZputhSdQ6X7QUIkwOnrjb4MmCMc5GgL3LN7tVUAB1jOo9BxpKwA/w640-h542/%E6%88%AA%E5%9C%96%202024-05-03%20%E4%B8%8A%E5%8D%8811.10.14.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;是可以成功的讀取其中的資料。&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Tonny左下角這個小視窗（circuitPython設備）可以顯示開發板的儲存空間。在執行上列程式後，如下圖，重新整理circuitPython設備，可以發現這個小視窗多出了一個目錄/sd，其下還有一個檔案data.txt。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSmpVwPdagEYe6A9eX3kOXgCcvk_n0F2lDAJPM0JM2_LG7ix3gL-VgsC7jcm82X7M0N-hRd7gC_EHou4S7Fv_dkWZ96TI9mI01_SgaebEzOF3eaJe_UH5z5Gipkqxu3NIqrrZdpr04435dyVmYodZSZgXDSLkwEK3M_l38F2EwKZqBs5lAigfSfnhVq40/s486/%E6%88%AA%E5%9C%96%202024-05-03%20%E4%B8%8A%E5%8D%8811.15.15.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;368&quot; data-original-width=&quot;486&quot; height=&quot;303&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSmpVwPdagEYe6A9eX3kOXgCcvk_n0F2lDAJPM0JM2_LG7ix3gL-VgsC7jcm82X7M0N-hRd7gC_EHou4S7Fv_dkWZ96TI9mI01_SgaebEzOF3eaJe_UH5z5Gipkqxu3NIqrrZdpr04435dyVmYodZSZgXDSLkwEK3M_l38F2EwKZqBs5lAigfSfnhVq40/w400-h303/%E6%88%AA%E5%9C%96%202024-05-03%20%E4%B8%8A%E5%8D%8811.15.15.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;在這個檔案上點２下，會打開它，看到其內容，確實是如我們寫的程式所輸出的有２行資料。這一點是Tonny這個環境，我覺得很好用的功能！我們也可以在這裡直接編修這個data.txt檔案，編完是可以儲存的。（是真的存回micro SD裡面）&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOwfD61n9eq0iSZEY3YpmbiCvLb7zzYiH8MnzjqUrSwqnLh70kymA9T_IRmEOVsCR4zRQGQtmQIpm8xY8kMtVtbBYEduRHX640v7mGCBeY-cA1jFKRMeTruSdAoruixpYjdYoJxUcE7NaZ8qNv2x-WUrKBJQlgQbtIibjs_QHiRcBdvARE5wxWMjDeHLk/s1094/%E6%88%AA%E5%9C%96%202024-05-03%20%E4%B8%8A%E5%8D%8811.25.18.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;926&quot; data-original-width=&quot;1094&quot; height=&quot;542&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOwfD61n9eq0iSZEY3YpmbiCvLb7zzYiH8MnzjqUrSwqnLh70kymA9T_IRmEOVsCR4zRQGQtmQIpm8xY8kMtVtbBYEduRHX640v7mGCBeY-cA1jFKRMeTruSdAoruixpYjdYoJxUcE7NaZ8qNv2x-WUrKBJQlgQbtIibjs_QHiRcBdvARE5wxWMjDeHLk/w640-h542/%E6%88%AA%E5%9C%96%202024-05-03%20%E4%B8%8A%E5%8D%8811.25.18.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;當然，我們寫的程式也可以對這個檔案做寫入的動作，應該就是：&lt;div&gt;open(&#39;/sd/data.txt&#39;,&#39;r&#39;)改為open(&#39;/sd/data.txt&#39;,&#39;w&#39;)或者open(&#39;/sd/data.txt&#39;,&#39;a&#39;)，然後用write()之類的指令來操作即可。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/8559021615282263748/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/8559021615282263748?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/8559021615282263748'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/8559021615282263748'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2024/05/pca10059-nrf52840-dongle-circuitpython.html' title='pca10059 (nRF52840 Dongle) + circuitPython + micro SD card 讀取或寫入資料'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhq9KPwEExQ8lilV8eL0RLddl-8uYcpdf8OHaYZQ9U1NXj4U4nI7q_PAtMrtjiCtvpxMi4EU3maBCku5WyHIBWaVxMN6_2P-kDpC7uGsu1QbB27ENf7dMQGA_wpK9fvGHMIrAISxzSJv1wYWO9htyyQQcpRYIx0PbR7mYAkP-G2yClDI96jSLKbCej3rVY/s72-c/%E6%88%AA%E5%9C%96%202024-05-02%20%E4%B8%8A%E5%8D%8811.17.58.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-6113402848939827543</id><published>2023-12-27T11:06:00.008+08:00</published><updated>2023-12-27T11:13:35.489+08:00</updated><title type='text'>Oracle 11g R2 突然無法連入事件 (CLOSE_WAIT, TIME_WAIT)</title><content type='html'>&lt;p&gt;&amp;nbsp;昨日我們一台Oracle 11g主機突然無法連入, 檢查後發現用SSH連入主機正常, 在主機上存取Oracle也都正常, 主機CPU, 記憶體, HD用量也都正常。只有透過網路存取Oracle的連線變得很難連上, 有時等很久之後可以連上。同事直接重開該台主機(shutdown, reboot)後, 就可以正常連上, 但沒多久又發現同樣連不上的情況!&lt;/p&gt;&lt;p&gt;我將listener 關下, 再打開後, 也一樣正常一下子, 然後就又連不上了。同事發現listener log檔已經非常大, 決定將log檔copy走, 刪除, 讓log檔重新開始。但是重開listener後, 情況一樣沒改善! 此時, listener log檔內可以看到一些錯誤訊息:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;shell&quot;&gt;&lt;p&gt;26-DEC-2023 12:02:54 * (CONNECT_DATA=(SERVICE_NAME=orcl)(CID=(PROGRAM=c:\windows\system32\inetsrv\w3wp.exe)(HOST=xxxx&lt;/p&gt;&lt;p&gt;)(USER=NETWORK?SERVICE))) * (ADDRESS=(PROTOCOL=tcp)(HOST=10.xx.xx.xx)(PORT=1234)) * establish * orcl * 12518&lt;/p&gt;&lt;p&gt;TNS-12518: TNS:listener could not hand off client connection&lt;/p&gt;&lt;p&gt;&amp;nbsp;TNS-12547: TNS:lost contact&lt;/p&gt;&lt;p&gt;&amp;nbsp; TNS-12560: TNS:protocol adapter error&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp;TNS-00517: Lost contact&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; Linux Error: 32: Broken pipe&lt;/p&gt;&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;使用netstat -ant, netstat -anp | grep 1521 或者lsof -i:1521查看會發現有很多TCP/IP連線的狀態一直都呈現TIME_WAIT, CLOSE_WAIT之類的的不正常狀態, 而且很多都不會消失, 還愈來愈多!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;shell&quot;&gt;&lt;p&gt;tcp&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 0&amp;nbsp; &amp;nbsp; &amp;nbsp; 0 127.0.0.1:62333&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;127.0.0.1:1521&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ESTABLISHED 4316/ora_pmon_orcl&lt;/p&gt;&lt;p&gt;tcp&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 0&amp;nbsp; &amp;nbsp; &amp;nbsp; 0 :::1521&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;:::*&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; LISTEN&amp;nbsp; &amp;nbsp; &amp;nbsp; 15722/tnslsnr&lt;/p&gt;&lt;p&gt;tcp&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 0&amp;nbsp; &amp;nbsp; &amp;nbsp; 0 ::ffff:127.0.0.1:1521&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;::ffff:127.0.0.1:46823&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;b&gt;&lt;span style=&quot;color: #2b00fe;&quot;&gt;TIME_WAIT&lt;/span&gt;&lt;/b&gt;&amp;nbsp; &amp;nbsp;-&lt;/p&gt;&lt;p&gt;tcp&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 0&amp;nbsp; &amp;nbsp; &amp;nbsp; 0 ::ffff:127.0.0.1:56882&amp;nbsp; &amp;nbsp; &amp;nbsp; ::ffff:127.0.0.1:1521&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ESTABLISHED 9781/java&lt;/p&gt;&lt;p&gt;tcp&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 0&amp;nbsp; &amp;nbsp; &amp;nbsp; 0 ::ffff:127.0.0.1:1521&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;::ffff:127.0.0.1:56882&amp;nbsp; &amp;nbsp; &amp;nbsp; ESTABLISHED 16245/oracleorcl&lt;/p&gt;&lt;p&gt;tcp&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 0&amp;nbsp; &amp;nbsp; &amp;nbsp; 0 ::ffff:127.0.0.1:1521&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;::ffff:127.0.0.1:56880&amp;nbsp; &amp;nbsp; &amp;nbsp; ESTABLISHED 16241/oracleorcl&lt;/p&gt;&lt;p&gt;tcp&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 0&amp;nbsp; &amp;nbsp; &amp;nbsp; 0 ::ffff:127.0.0.1:1521&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;::ffff:127.0.0.1:46824&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;b&gt;&lt;span style=&quot;color: #2b00fe;&quot;&gt;TIME_WAIT&lt;/span&gt;&lt;/b&gt;&amp;nbsp; &amp;nbsp;-&lt;/p&gt;&lt;p&gt;tcp&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 0&amp;nbsp; &amp;nbsp; &amp;nbsp; 0 ::ffff:127.0.0.1:1521&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;::ffff:127.0.0.1:56881&amp;nbsp; &amp;nbsp; &amp;nbsp; ESTABLISHED 16243/oracleorcl&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;懷疑是tnslsnr出了問題, 找了一下網路上其他人相似的情況, 發現大陸的朋友有提到:&lt;a href=&quot;https://blog.csdn.net/starshine/article/details/16881859&quot; target=&quot;_blank&quot;&gt;https://blog.csdn.net/starshine/article/details/16881859&lt;/a&gt;, 他的解決方法看來也只是關掉tnslsnr, 再重新打開, 和我們唯一的不同是他用kill指令把tnslsnr process kill掉, 其他都一樣。不過, 這可能也是一個重點, 也許kill process才能完全把佔用的TCP/IP連線都清乾淨!&amp;nbsp;&lt;/p&gt;&lt;p&gt;另一位朋友&lt;a href=&quot;https://medium.com/@brad_24220/time-wait-mitigating-tcp-ip-connection-exhaustion-c1a18080dc70&quot; target=&quot;_blank&quot;&gt;https://medium.com/@brad_24220/time-wait-mitigating-tcp-ip-connection-exhaustion-c1a18080dc70&lt;/a&gt;的方法比較有意思, 他在/etc/sysctl.conf檔加入了一些設定(針對Oracle Linux 7/8):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;shell&quot;&gt;
net.netfilter.nf_conntrack_tcp_timeout_time_wait=1
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_fin_timeout=1
&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;他說: &quot;&lt;span style=&quot;color: #ffa400;&quot;&gt;TIME_WAIT是TCP / IP堆棧中令人難以置信的部分,它使連接一直存在,直到客戶端正確關閉連接為止。但是,在某些情況下,客戶端無法正確或有效地關閉連接。這可能導致TIME_WAIT狀態下的TCP連接持續存在,直到操作系統清除它們為止。對於繁忙的系統,這可能會導致主機拒絕服務,因為所有可用的連接都綁在TIME_WAIT狀態下。&lt;/span&gt;&quot;&lt;/p&gt;&lt;p&gt;使用vi將以上設定加入至/etc/sysctl.conf檔, 然後下 sysctl -p 指令, 我發現系統只接受後面2行, 第一行net.netfilter.nf_conntrack_tcp_timeout_time_wait=1不被接受, (可能是我的Linux版本較舊!) 將其mark掉 (#) 存檔, 再下一次 sysctl -p, 確定沒問題後, 去kill tnslsnr process, 再下lsnrctl start, 問題就解決了, 觀察一陣子, 可以看到相關的TCP/IP連線出現TIME_WAIT狀態後, 都會在1分鐘內被清掉。不再有連線進不去的問題出現!&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/6113402848939827543/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/6113402848939827543?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/6113402848939827543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/6113402848939827543'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2023/12/oracle-11g-r2-closewait-timewait.html' title='Oracle 11g R2 突然無法連入事件 (CLOSE_WAIT, TIME_WAIT)'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-1442076326715786211</id><published>2023-12-20T11:32:00.001+08:00</published><updated>2023-12-20T11:32:16.159+08:00</updated><title type='text'>基金日記: 基金的績效怎麼看?</title><content type='html'>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4ol0mBxmxuk4uD-u83KpqghZj-hVUCzbGTfDcSimbE3i8TdRuSdpcWS2pUW1ZkN993oWUQx36sgsMlBPGMHi-JPVJwEValKI6cSikB12PC81CVGlFPvEWmL8E-ImYtLrACowUkPimzCuLNf48XuPEKBpPohh1ZAbVds7WUXgQf6Nh3XaENbRPpZyb6yY/s786/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-12-20%20102921.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;606&quot; data-original-width=&quot;786&quot; height=&quot;494&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4ol0mBxmxuk4uD-u83KpqghZj-hVUCzbGTfDcSimbE3i8TdRuSdpcWS2pUW1ZkN993oWUQx36sgsMlBPGMHi-JPVJwEValKI6cSikB12PC81CVGlFPvEWmL8E-ImYtLrACowUkPimzCuLNf48XuPEKBpPohh1ZAbVds7WUXgQf6Nh3XaENbRPpZyb6yY/w640-h494/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-12-20%20102921.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;這支基金成立至今2年多, 成立時正好是FED為了因應全球Covid-19疫情造成的全球經濟困局, 而大量印鈔的時候。當時, FED救市, 直昇機式的大撒幣, 美國人手上現金滿滿, 股票市場熱鬧。利率降到0, 如下圖。此時也成就了不少少年股神!&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoCjhWiqJUMkpx-XBBrwU7nIoGsaBQ547eLY-T5RKxtcVzginDc3GH9r1AF0HQoWk1VriPyBwiUBCTzfDMj3q8EgHVO4F03MUsBEIe-3mlbY10Mv5ahTcpgLwM8GXJzTWivtNIL3k6ii_otyBL76iQ83me4joCaGmNB11UXsYjsxXM1P1pkGGtyPhATUM/s1032/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-12-20%20103716.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;522&quot; data-original-width=&quot;1032&quot; height=&quot;324&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoCjhWiqJUMkpx-XBBrwU7nIoGsaBQ547eLY-T5RKxtcVzginDc3GH9r1AF0HQoWk1VriPyBwiUBCTzfDMj3q8EgHVO4F03MUsBEIe-3mlbY10Mv5ahTcpgLwM8GXJzTWivtNIL3k6ii_otyBL76iQ83me4joCaGmNB11UXsYjsxXM1P1pkGGtyPhATUM/w640-h324/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-12-20%20103716.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;但接著, 通膨就來了, FED為了對抗通膨, 已開始有傳出要升息的聲音。那時, 我對基金公司在此時成立這支基金, 心裡就有一些疑問? 這種全球趨勢的基金, 又不是反做或平衡型, 以趨勢來看, 不是正好去接掉下來的刀子嗎? 但因為理專的推銷, 我就意思意思的買一點點, 反正當做一個指標來觀察也好。&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;果然, FED開始升息後, 其淨值就開始掉掉掉, 到現在2年多, FED抗通膨有了一些成果, 開始傳出明年會啟動降息的消息, 這個基金的淨值就慢慢的回升。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;現在事後諸葛一下, 檢討如何操作才是比較好的策略:&amp;nbsp;&lt;/div&gt;&lt;div&gt;1. 一般人會想, 買在最低, 賣在最高是最好的策略, 但這個策略的問題在於, 沒有人知道什麼時候是最低點, 什麼時候是最高點。所以, 理論很好, 但現實不可行。&lt;/div&gt;&lt;div&gt;2. 一個說法是最好的買點是十年前, 其次是今天。但這個策略的問題是, 很可能買在最高點, 當然也很可能買在最低點, 反正全看運氣。&lt;/div&gt;&lt;div&gt;3. 我想, 應該盡可能買在低點, 利用一些工具來提高猜測的準確度, 就可以有不差的效果。以FED的利率來看, 升息開始後約半年, 就是基金淨值的最低點。到利率最高點時, 淨值都是向上的走法。當然此期間, 淨值還是上上下下的走。這段期間, 如果定期分批買進, 其實是會獲利的。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;配合基金的績效圖表來看, 孤注一擲的在2年前下好離手, 到現在就是-9.43%(虧錢)。那如果是孤注一擲的在1年前下好離手, 到現在就是29.18%(大賺錢), 即使在半年前孤注一擲, 至今也有8.14%。但這種策略其實很難實行! 因為很難猜到何時是最低點。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;實戰後, 會發現, 比較好實行的策略會是, 依照FED的利率, 配合全球景氣的相關數據, 定期(不)定額的買入。以績效圖表來看2年前就開始定期定額, 到現在也有15.61%, 就算是1年前開始到現在也有14.41%。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/1442076326715786211/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/1442076326715786211?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/1442076326715786211'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/1442076326715786211'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2023/12/blog-post.html' title='基金日記: 基金的績效怎麼看?'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4ol0mBxmxuk4uD-u83KpqghZj-hVUCzbGTfDcSimbE3i8TdRuSdpcWS2pUW1ZkN993oWUQx36sgsMlBPGMHi-JPVJwEValKI6cSikB12PC81CVGlFPvEWmL8E-ImYtLrACowUkPimzCuLNf48XuPEKBpPohh1ZAbVds7WUXgQf6Nh3XaENbRPpZyb6yY/s72-w640-h494-c/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-12-20%20102921.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-2077377821398632936</id><published>2023-12-01T13:44:00.005+08:00</published><updated>2023-12-01T13:44:37.083+08:00</updated><title type='text'>nRF52840 Dongle CircuitPython  類比輸入腳位</title><content type='html'>&lt;p&gt;&amp;nbsp;如同大多數的MCU只有特定幾支腳有支援類比輸入的功能， nRF52840 Dongle 也是只有幾支腳位有類比輸入功能。但其實我也懶得查文件，所以就直接測試看看：&lt;/p&gt;&lt;p&gt;進入REPL，輸入指令：&lt;/p&gt;&lt;p&gt;&amp;gt;&amp;gt;&amp;gt; import board&lt;/p&gt;&lt;p&gt;&amp;gt;&amp;gt;&amp;gt; from analogio import AnalogIn&lt;/p&gt;&lt;p&gt;&amp;gt;&amp;gt;&amp;gt; analog_in = AnalogIn(board.P1_10)&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: red;&quot;&gt;Traceback (most recent call last):&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: red;&quot;&gt;&amp;nbsp; File &quot;&amp;lt;stdin&amp;gt;&quot;, line 1, in &amp;lt;module&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: red;&quot;&gt;ValueError: Invalid pin&lt;/span&gt;&lt;/p&gt;&lt;p&gt;這樣P1_10 (即下圖中的左下角 1.10 Pin) 這支腳位就是不支援的，如此，有點耐心的一支腳一支腳的試，全部試完，就知道了，：-）&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSHQCSDFqZpB1p1nEhiBN5KnSYiYgVZ7sTLrZLwbYI0h52ISM-QSRs1qLhJjSsps0fcotY2xoXQjgvSbIe4MW4mK5eliBlAOXGRD55XQAwWDHyFoN1zbTZyRb1H8Q2AEoMymnQFz2UY63BTFdVESGeKSZqRSIkMX2JQ_6hCz00ZMywa2Wu02_W8isKX14/s870/%E6%88%AA%E5%9C%96%202023-12-01%20%E4%B8%8B%E5%8D%881.19.18.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;353&quot; data-original-width=&quot;870&quot; height=&quot;260&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSHQCSDFqZpB1p1nEhiBN5KnSYiYgVZ7sTLrZLwbYI0h52ISM-QSRs1qLhJjSsps0fcotY2xoXQjgvSbIe4MW4mK5eliBlAOXGRD55XQAwWDHyFoN1zbTZyRb1H8Q2AEoMymnQFz2UY63BTFdVESGeKSZqRSIkMX2JQ_6hCz00ZMywa2Wu02_W8isKX14/w640-h260/%E6%88%AA%E5%9C%96%202023-12-01%20%E4%B8%8B%E5%8D%881.19.18.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&amp;gt;&amp;gt;&amp;gt; analog_in = AnalogIn(board.P0_31)&lt;/p&gt;&lt;p&gt;&amp;gt;&amp;gt;&amp;gt; analog_in = AnalogIn(board.P0_29)&lt;/p&gt;&lt;p&gt;&amp;gt;&amp;gt;&amp;gt; analog_in = AnalogIn(board.P0_02)&lt;/p&gt;&lt;p&gt;結果，只有這3支腳位 (0.02, 0.29, 0.31) 沒有出現錯誤訊息。&lt;/p&gt;&lt;p&gt;那應該就是這樣了，之後找時間，實際接個電路來試試。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/2077377821398632936/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/2077377821398632936?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/2077377821398632936'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/2077377821398632936'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2023/12/nrf52840-dongle-circuitpython.html' title='nRF52840 Dongle CircuitPython  類比輸入腳位'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSHQCSDFqZpB1p1nEhiBN5KnSYiYgVZ7sTLrZLwbYI0h52ISM-QSRs1qLhJjSsps0fcotY2xoXQjgvSbIe4MW4mK5eliBlAOXGRD55XQAwWDHyFoN1zbTZyRb1H8Q2AEoMymnQFz2UY63BTFdVESGeKSZqRSIkMX2JQ_6hCz00ZMywa2Wu02_W8isKX14/s72-w640-h260-c/%E6%88%AA%E5%9C%96%202023-12-01%20%E4%B8%8B%E5%8D%881.19.18.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-1632396665985353747</id><published>2023-08-24T15:56:00.012+08:00</published><updated>2023-08-25T10:22:30.382+08:00</updated><title type='text'>由Python程式來存取Google sheets (試算表)</title><content type='html'>&lt;p&gt;&amp;nbsp;可以在Raspberry Pi上讀取TMP102的温度值後, 我想要把温度值存放在那裡? 存在本機的檔案上, 網路上已有現成Python程式, 放在MQTT Server, 以前就玩過。想到放到Google 試算表應該也不錯, 以前也沒試過, 不如來試試!&lt;/p&gt;&lt;p&gt;首先找到這一貼文&lt;a href=&quot;https://erikrood.com/Posts/py_gsheets.html&quot; target=&quot;_blank&quot;&gt;Reading and writing to Google Spreadsheets using Python&lt;/a&gt;, 此文言簡意賅, 只有3個步驟就做完, 文章印出來也只要2頁! 但是第一個步驟因為要操作&lt;a href=&quot;https://console.developers.google.com/&quot; target=&quot;_blank&quot;&gt;Google API Console&lt;/a&gt;, 而這個網頁看來操作方式有些修改過了, 所以照著做會有些困難。自己摸索一陣時間後, 才弄清楚! 其實網路上討論這個部份的貼文不少,&amp;nbsp;&lt;a href=&quot;https://www.wongwonggoods.com/all-posts/python/python_web_crawler/google-sheet-api/&quot; target=&quot;_blank&quot;&gt;【Python 網頁爬蟲 #1】設定 google sheet API 並取得 json 金鑰，讓我們的資料能同步更新至雲端 google sheet 表格 (內含完整圖片說明)&lt;/a&gt;這篇貼文就很詳細, 文章是去年寫的, 還算新, Google API Console的操作界面和現在的一致。另外,&amp;nbsp;&lt;a href=&quot;https://python.plainenglish.io/read-and-write-google-sheets-data-from-python-d825617673e0&quot; target=&quot;_blank&quot;&gt;How to Read and Write Google Sheets Data Using Python&lt;/a&gt;這篇貼文在設定Google Cloud Console部份, 描述的更詳細, 而且Python程式部份使用不同的套件。還有一篇陳濤半年前寫的&lt;a href=&quot;https://hackmd.io/@yun-tao/B12j7VmCs&quot; target=&quot;_blank&quot;&gt;[筆記] 使用 pygsheets 記錄實驗數據到 google sheet&lt;/a&gt;也很不錯, 特別是把Python pygsheets套件的幾個常用操作點出, 值得看一下。&lt;/p&gt;&lt;p&gt;我就不重複講了, 只提幾個重點:&lt;/p&gt;&lt;p&gt;===&amp;nbsp; 步驟 1 ===&lt;/p&gt;&lt;p&gt;1. 要先建專案&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbHhFQw0gXzZb-gwjHroJHhsRme8UNpdZAXE_U0Pg2b71aK8qth02uQCLVrJ5YcZWLfyXLtVtwELVHm3tlWaLQ9ROVB4V35VpeAIhhI1KCOyN1u-VfWhxLJvipUX4A2FNb2wR3WiqYJZZgmuifgz80VUWgk-bn-_hMucxYcblaM3wZrzDPDEhuRD1MBVU/s1538/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-24%20151849.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;826&quot; data-original-width=&quot;1538&quot; height=&quot;344&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbHhFQw0gXzZb-gwjHroJHhsRme8UNpdZAXE_U0Pg2b71aK8qth02uQCLVrJ5YcZWLfyXLtVtwELVHm3tlWaLQ9ROVB4V35VpeAIhhI1KCOyN1u-VfWhxLJvipUX4A2FNb2wR3WiqYJZZgmuifgz80VUWgk-bn-_hMucxYcblaM3wZrzDPDEhuRD1MBVU/w640-h344/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-24%20151849.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;2. 在建好的專案裡, 啟用2個API。Google Drive API, Google Sheets API (有些文章只提到要啟用Google Sheets API, 那就要看你之後的程式的寫法, 我因為後面Python程式有用到, 所以要這2個都啟用)&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaTss-zMYJw7kJxAM_5KHmi8JIrpM_IuNg5O2Tl-aE4nmglkFM7pJz2mVG8AVUJ2cxOMX-NOdaFpchdleFTafq_sbgpQfsuYqHJ1VraNokk1iTlQN1gVuJt84jkuWGrc6CjjeEfj0fXMJIWgXa_C2USQTOlz6bacFU3h9EpDsXctcv2sNZ0QJCscuL9Mw/s1528/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-24%20152123.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;787&quot; data-original-width=&quot;1528&quot; height=&quot;330&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaTss-zMYJw7kJxAM_5KHmi8JIrpM_IuNg5O2Tl-aE4nmglkFM7pJz2mVG8AVUJ2cxOMX-NOdaFpchdleFTafq_sbgpQfsuYqHJ1VraNokk1iTlQN1gVuJt84jkuWGrc6CjjeEfj0fXMJIWgXa_C2USQTOlz6bacFU3h9EpDsXctcv2sNZ0QJCscuL9Mw/w640-h330/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-24%20152123.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;3. 建立憑證 (有3個可以選: API, OAuth ID, 服務帳戶。要選服務帳戶, 建完後會得到一個電子郵件地址, 類似&lt;span style=&quot;background-color: white; font-family: Roboto; font-size: 13px;&quot;&gt;xxx@xxx.iam.gserviceaccount.com&lt;/span&gt;)&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFcpWpdvQ4xVCQN_10oy7daWIK7LxOHDXvlASRVbjV8870D2NnqmD5gH2dmj-rGJsAnTD2Et4hDgFJpijY9SVZTEmcNWGToDnlEzSM9afE8cMg7kRerqfb7ilOSiIiOEXv0YoD7Gh73SD267NO2gd9K1fkAS88WuoGt2kQup3DcQ4dluXrbga0heAG3V8/s1534/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-24%20152951.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;616&quot; data-original-width=&quot;1534&quot; height=&quot;258&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFcpWpdvQ4xVCQN_10oy7daWIK7LxOHDXvlASRVbjV8870D2NnqmD5gH2dmj-rGJsAnTD2Et4hDgFJpijY9SVZTEmcNWGToDnlEzSM9afE8cMg7kRerqfb7ilOSiIiOEXv0YoD7Gh73SD267NO2gd9K1fkAS88WuoGt2kQup3DcQ4dluXrbga0heAG3V8/w640-h258/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-24%20152951.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyPRCFwER55LKwnI13L8__MJtd6V6CehwPrZBftjVBi55r8WA5GQlVPYUm2oTQ-pR2cx6lmExJROIgA2OYq7r9pOm8oVpwkW9JGFLJqIlFydkuz1Sp8nASK0k8tyyT0CMKcnQ0RvaTYv6SkMeNemNO8hUGRT1xw7QRalsTL8XVlMgVmmaJ3N6r5jw0r7I/s1524/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-24%20153653.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;657&quot; data-original-width=&quot;1524&quot; height=&quot;276&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyPRCFwER55LKwnI13L8__MJtd6V6CehwPrZBftjVBi55r8WA5GQlVPYUm2oTQ-pR2cx6lmExJROIgA2OYq7r9pOm8oVpwkW9JGFLJqIlFydkuz1Sp8nASK0k8tyyT0CMKcnQ0RvaTYv6SkMeNemNO8hUGRT1xw7QRalsTL8XVlMgVmmaJ3N6r5jw0r7I/w640-h276/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-24%20153653.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;4. 針對這個服務帳戶, 建立金鑰, 並下載其JSON檔案 (命名為creds.json)&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgXGJ1Ig8q5ZhOaEok919XGzuHHRBFhZLlTtN3j8IXYG-jNvMOiaq7qhp61hjCsG2Cqx72lTBQJpsS44OFjBkvdHP1UeBQm769_1oFXOuoCLJkFe5o0bHMfGMfqeZ2w4eDvHeegC-cnGZbFuiBeSIB-oLzGM2AHky0wGNqNJ-mx1AabMJpVLJTCilBVoc/s1530/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-24%20154426.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;705&quot; data-original-width=&quot;1530&quot; height=&quot;294&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgXGJ1Ig8q5ZhOaEok919XGzuHHRBFhZLlTtN3j8IXYG-jNvMOiaq7qhp61hjCsG2Cqx72lTBQJpsS44OFjBkvdHP1UeBQm769_1oFXOuoCLJkFe5o0bHMfGMfqeZ2w4eDvHeegC-cnGZbFuiBeSIB-oLzGM2AHky0wGNqNJ-mx1AabMJpVLJTCilBVoc/w640-h294/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-24%20154426.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;5. 到Google 試算表去, 建一個新文件(這裡, 我選一個好記的文件檔名: gsheet test), 或選一個你想用來被Python程式存取的文件。按右上角的&quot;共用&quot;, 新增之前建立的服務帳戶的郵件地址, 就是類似&lt;span style=&quot;background-color: white; font-family: Roboto; font-size: 13px;&quot;&gt;xxx@xxx.iam.gserviceaccount.com&lt;/span&gt;的那個。這樣, 這個試算表文件就可以被這個服務帳戶存取了。&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFHADNFc0wAFtUxiBsmWODhTqRnUHJQY_cwbrJ5M-SyHyHY8QgAPuOEMqpJo3yhrEFwZsAv-GT-fFov0AsIxbjXze_Gif8fqMvUZhi1LFURZuvuobf33ujN7IMzuxqWDOHTRr8GdIRIoHJainW-ySkexJnA4uIeCOP6UcCjytgGMqqXVvhCLVDf2VFAC8/s1313/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-24%20155007.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;743&quot; data-original-width=&quot;1313&quot; height=&quot;362&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFHADNFc0wAFtUxiBsmWODhTqRnUHJQY_cwbrJ5M-SyHyHY8QgAPuOEMqpJo3yhrEFwZsAv-GT-fFov0AsIxbjXze_Gif8fqMvUZhi1LFURZuvuobf33ujN7IMzuxqWDOHTRr8GdIRIoHJainW-ySkexJnA4uIeCOP6UcCjytgGMqqXVvhCLVDf2VFAC8/w640-h362/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-24%20155007.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;===&amp;nbsp; 步驟 2 ===&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;可以來寫Python程式了, 我在Raspberry Pi上面操作, 首先要把之前服務帳戶的金鑰creds.json檔案存到Raspberry Pi機器上面去。這可以用scp指令來完成。&lt;/div&gt;&lt;div&gt;$ scp creds.json ops@192.168.1.2:creds.json&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;接著Python程式會用到的套件要裝一下:&lt;/div&gt;&lt;div&gt;$ sudo pip install pygsheets&lt;/div&gt;&lt;div&gt;$ sudo pip install pandas&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;用指令模式來嘗試: (配合的試算表文件要先建4個工作表!)&lt;/div&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;
&lt;div&gt;$ python3&lt;/div&gt;&lt;div&gt;&lt;div&gt;Python 3.9.2 (default, Feb 28 2021, 17:03:44)&lt;/div&gt;&lt;div&gt;[GCC 10.2.1 20210110] on linux&lt;/div&gt;&lt;div&gt;Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; import pygsheets&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; import pandas as pd&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; gc = pygsheets.authorize(service_file=&#39;creds.json&#39;)&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; df = pd.DataFrame()&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; df[&#39;name&#39;] = [&#39;John&#39;, &#39;Steve&#39;, &#39;Sarah&#39;]&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; sh = gc.open(&#39;gsheet test&#39;)&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks = sh[1]&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.set_dataframe(df,(1,1))&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; df[&#39;name&#39;] = [&#39;John&#39;, 29.5, 30.3]&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks = sh[2]&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.set_dataframe(df,(1,1))&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.set_dataframe(df,(2,1))&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.set_dataframe(df,(1,2))&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.set_dataframe(df,(1,3))&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.update_value(&#39;A7&#39;, 29.3)&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks = sh[3]&lt;/div&gt;&lt;div&gt;...&lt;/div&gt;&lt;div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.insert_rows(7, number=1, values=[&#39;17:08&#39;,24.5])&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.insert_rows(8, number=1, values=[&#39;17:09&#39;,23.5])&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.insert_rows(9, number=1, values=[&#39;17:10&#39;,21.2])&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.insert_rows(10, number=1, values=[&#39;17:12&#39;,25.2])&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.insert_rows(11, number=1, values=[&#39;17:12&#39;,22.2])&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.insert_rows(12, number=1, values=[&#39;17:13&#39;,20.7])&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.insert_rows(13, number=1, values=[&#39;17:14&#39;,23.2])&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.insert_rows(14, number=1, values=[&#39;17:15&#39;,24.2])&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.insert_rows(15, number=1, values=[&#39;17:16&#39;,22.2])&lt;/div&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; wks.insert_rows(16, number=1, values=[&#39;17:17&#39;,20.8])&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;===&amp;nbsp; 步驟 3 ===&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;打開Google 試算表, 觀察, 可以看到在Python寫入的資料, 出現在指定的試算表文件中了。&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1md9IOWm1hcMFPVzMtqfx_vdwQdbCw5gkevbedHgocwT4Se1UsxybzrxUlbe4ndoH12suDVXg3qV7tEOJEScYHVvft_LpB0Wm8AibnbAJTEjP43SnWLgfKOkPB_4eUMuKJeTD2odXvF-RVwcsNSM80Rj22PwuQg_phAWHJPMZXwcKZ2hQ7Il63aKIKlE/s1308/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-24%20161429.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;575&quot; data-original-width=&quot;1308&quot; height=&quot;282&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1md9IOWm1hcMFPVzMtqfx_vdwQdbCw5gkevbedHgocwT4Se1UsxybzrxUlbe4ndoH12suDVXg3qV7tEOJEScYHVvft_LpB0Wm8AibnbAJTEjP43SnWLgfKOkPB_4eUMuKJeTD2odXvF-RVwcsNSM80Rj22PwuQg_phAWHJPMZXwcKZ2hQ7Il63aKIKlE/w640-h282/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-24%20161429.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;到這裡, 結合之前取得TMP102温度值的方法和這裡的作法, 就可以做出一個即時回報温度值的自動機制, 而我們可以在任何地點, 任何時間, 只要能存取網路, 就可以由Google試算表查看最新狀況了。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;具體作法:&lt;/div&gt;&lt;div&gt;這個試算表文件放1年份的資料, 每個月的資料放在一個工作表, 所以最多可能有12個工作表, 命名為01, 02, ..., 12。每個工作表最多可能有31天的資料, 每天24小時x60分鐘/5分鐘=288筆資料。所以一個月最多有288x31=8928筆資料。我們只要知道現在的日期時間, 就可以知道資料要放在那個工作表的那個位置上。&lt;/div&gt;&lt;div&gt;由上面Python程式改寫, 在連上Google試算表, 打開文件後(&lt;span style=&quot;font-family: monospace; white-space: pre;&quot;&gt;sh = gc.open(&#39;gsheet test&#39;)&lt;/span&gt;)可先取得該文件的工作表list (wks_list = sh.worksheets()), 由此可以檢查是否已存在所需要的工作表, 若不存在則建立該工作表(&lt;span style=&quot;color: inherit; font-family: Menlo, Monaco, Consolas, &amp;quot;Courier New&amp;quot;, monospace; font-size: 13.6px; letter-spacing: 0.35px;&quot;&gt;sh.add_worksheet(sheet_name, rows=N)&lt;/span&gt;), 否則就往下跑。&lt;/div&gt;&lt;div&gt;取得温度值後, 加上已知的日期和時間, 就可以把資料放到該特定位置。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;例如:1月的1號00:05, 就會是放在工作表&#39;01&#39;的第1筆, 所以:&lt;/div&gt;&lt;div&gt;wks = sh[0]&lt;/div&gt;&lt;div&gt;wks.insert_rows(1, number=1, values=[&#39;1&#39;, &#39;00:05&#39;,24.5])&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;有些小細節還要修改, 但大致上這個想法應該可行。&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/1632396665985353747/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/1632396665985353747?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/1632396665985353747'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/1632396665985353747'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2023/08/pythongoogle-sheets.html' title='由Python程式來存取Google sheets (試算表)'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbHhFQw0gXzZb-gwjHroJHhsRme8UNpdZAXE_U0Pg2b71aK8qth02uQCLVrJ5YcZWLfyXLtVtwELVHm3tlWaLQ9ROVB4V35VpeAIhhI1KCOyN1u-VfWhxLJvipUX4A2FNb2wR3WiqYJZZgmuifgz80VUWgk-bn-_hMucxYcblaM3wZrzDPDEhuRD1MBVU/s72-w640-h344-c/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-24%20151849.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-8531364829517007421</id><published>2023-08-16T17:58:00.023+08:00</published><updated>2023-08-18T09:27:39.702+08:00</updated><title type='text'>How to add (and remove) Tmp102 sensor to Raspberry Pi 4</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX4qTxnxVV13jipS38zrfSJ-jclSUIeXhnVMaOZ0JvsFR4_8Al9sBqHiRQMYEeUzzAFCgB6tz1JtyugqVNV6u8zBpHyZE7fBd2aLEl5OM9HqTR5rx_5MeIokwGlCcsyhJPro4W3DFhQNMxc-p9y2FbB3PGtWUvP86qoeQp0REQzJkzkryH2wjfrL4fWCc/s724/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-17%20085538.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;505&quot; data-original-width=&quot;724&quot; height=&quot;446&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX4qTxnxVV13jipS38zrfSJ-jclSUIeXhnVMaOZ0JvsFR4_8Al9sBqHiRQMYEeUzzAFCgB6tz1JtyugqVNV6u8zBpHyZE7fBd2aLEl5OM9HqTR5rx_5MeIokwGlCcsyhJPro4W3DFhQNMxc-p9y2FbB3PGtWUvP86qoeQp0REQzJkzkryH2wjfrL4fWCc/w640-h446/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-17%20085538.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;(註: 此圖截自SparkFun文章:&amp;nbsp;&lt;a href=&quot;https://learn.sparkfun.com/tutorials/python-programming-tutorial-getting-started-with-the-raspberry-pi/experiment-4-i2c-temperature-sensor&quot; target=&quot;_blank&quot;&gt;Python Programming Tutorial: Getting Started with the Raspberry Pi&lt;/a&gt;, 本文的接線方式和此相似, 只是GND接到Pin 9, 而不是Pin 6, 因為Pin 6被散熱風扇佔走! )&lt;br /&gt;&lt;p&gt;將TMP102温度感測器連接到Raspberry Pi (R-pi), 之後就可以利用R-pi來監測環境温度。只是簡單的把環境温度記錄到log檔, 或者儲存到雲端讓人們隨時可透過網路查詢; 或者加上觸發條件在温度高於或低於特定值時可進行通知的動作。這些都是可以做的。本文先嘗試踏出第一步, 將TMP102接上R-pi, 讓系統可以存取其感測到的温度值, 也讓我們可以寫Python程式來存取温度值。&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.rpiblog.com/2012/07/raspberry-pi-temperature-sensor-using.html&quot; target=&quot;_blank&quot;&gt;Raspberry Pi temperature sensor using TMP102&lt;/a&gt;這篇貼文, 其實就在說明如何將TMP102連接到R-pi, 但因為Raspberry Pi出來很多年了, 出的板子種類也很多(2, 3, 4, Zero, Zero 2, etc), 同樣的在其上跑的OS也很多, 有官方的Raspberry Pi OS, Ubuntu, Freebsd, 等等。所以, 這文章以現在來說，有一些需要小修改的地方。&lt;/p&gt;&lt;p&gt;本文針對Raspberry Pi 4B, 使用官方Raspberry OS 64bit的環境，嘗試加入TMP102，基於以上所提文章做一些補充。&lt;/p&gt;&lt;p&gt;先進行以下設定:&lt;/p&gt;&lt;p&gt;1. Enable I2C&lt;/p&gt;&lt;p&gt;$ sudo&amp;nbsp;raspi-config&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjajTdLaDWF5B6xfZvII4Lcnkz4n4o8tyN5cCRmswt0sfKOXI49IkogMiyYhsuWU0Lg5OjR6hyon87QV48XDDo00310Q5u5IfSxZ2K98UE3sM-CK-3V-FdC8XtMRHS9OpyA63fSBFo0ICUFxTwLJ3ENBudnQxi5pbU7NKmladA08luhF6X7bDIZfB2PWkE/s1091/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-16%20172241.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;572&quot; data-original-width=&quot;1091&quot; height=&quot;336&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjajTdLaDWF5B6xfZvII4Lcnkz4n4o8tyN5cCRmswt0sfKOXI49IkogMiyYhsuWU0Lg5OjR6hyon87QV48XDDo00310Q5u5IfSxZ2K98UE3sM-CK-3V-FdC8XtMRHS9OpyA63fSBFo0ICUFxTwLJ3ENBudnQxi5pbU7NKmladA08luhF6X7bDIZfB2PWkE/w640-h336/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-16%20172241.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;選3 Interface Options&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKKs60EbHLB8Na5jzjXCE9V9V00InTE8OHT2jAfonFxHK6TO11DEEXR0-08L2Vt6QGWYZl3Rbmfc7NSGMGN1gi1HkcffMVWXASKqG7Wt7xmMja8NBP4IOVXp0ImeceHWAWyXolOJMuVdyNs86TLo2_Nybe0AxZYSvlBzO8s930MezEx3RlITStLXtLYnE/s1091/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-16%20172414.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;573&quot; data-original-width=&quot;1091&quot; height=&quot;336&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKKs60EbHLB8Na5jzjXCE9V9V00InTE8OHT2jAfonFxHK6TO11DEEXR0-08L2Vt6QGWYZl3Rbmfc7NSGMGN1gi1HkcffMVWXASKqG7Wt7xmMja8NBP4IOVXp0ImeceHWAWyXolOJMuVdyNs86TLo2_Nybe0AxZYSvlBzO8s930MezEx3RlITStLXtLYnE/w640-h336/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-16%20172414.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;然後選I5 I2C, 接下來會問你要enable I2C嗎? 選是.&lt;/p&gt;&lt;p&gt;往下記得重開機!&lt;/p&gt;&lt;p&gt;2. 安裝以下套件:&lt;/p&gt;&lt;p&gt;$ sudo&amp;nbsp;apt-get install lm-sensors&amp;nbsp; &amp;nbsp;(出現一些問題, 但不用管它!)&lt;/p&gt;&lt;p&gt;$ sudo apt-get install&amp;nbsp;i2c-tools&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;==================&lt;/p&gt;&lt;p&gt;硬體接線&lt;/p&gt;&lt;p&gt;==================&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAD-wjrogW3zxSNnG-STLbLxY7Upn0I4ccRtOC_hHlfEZsQoHw-9SPyuQmUzMlHa0SvVIbt_maik3e2vwQCBW7oxqUBwM_guF1xDBvTmlBEotvphjxn5eMob1tB-_-S0B_SeTqIYd5iWTztVbHTaFB9CEuEY58nogOnZNjELV5gwknjpRmdYaKR4Sxe70/s524/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-16%20173340.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;473&quot; data-original-width=&quot;524&quot; height=&quot;578&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAD-wjrogW3zxSNnG-STLbLxY7Upn0I4ccRtOC_hHlfEZsQoHw-9SPyuQmUzMlHa0SvVIbt_maik3e2vwQCBW7oxqUBwM_guF1xDBvTmlBEotvphjxn5eMob1tB-_-S0B_SeTqIYd5iWTztVbHTaFB9CEuEY58nogOnZNjELV5gwknjpRmdYaKR4Sxe70/w640-h578/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-16%20173340.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;TMP102模塊上的4支腳(VCC, SDA, SCL, GND), 分別接到Raspberry Pi GPIO的(1,3,5,9), 如上圖, 都在上面左方, 我打勾的4個腳位。記得接線前, 先把Raspberry Pi關機, 拔掉電源, 再接。&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;重開機後, 下i2cdetect -y 1指令:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJtFQqjn3TUDtGZlyNJ5kkZrJgP8ykRIqt2FpYLC-UWAOSABztpqSZeH0RNNzPkoizS_nkhWPvDEZ-8PGP-T4ZFd3GQdmyGCGOwpJ2VIGIYB8rWK3EhjLkBqYgrWqko_Cq5svq-SNx2w8Ejadpi7TeNmDj32Tg9-TZQWhX-Nb9JP3VUPq36jK5w7VcAEc/s1042/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-16%20174104.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;455&quot; data-original-width=&quot;1042&quot; height=&quot;280&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJtFQqjn3TUDtGZlyNJ5kkZrJgP8ykRIqt2FpYLC-UWAOSABztpqSZeH0RNNzPkoizS_nkhWPvDEZ-8PGP-T4ZFd3GQdmyGCGOwpJ2VIGIYB8rWK3EhjLkBqYgrWqko_Cq5svq-SNx2w8Ejadpi7TeNmDj32Tg9-TZQWhX-Nb9JP3VUPq36jK5w7VcAEc/w640-h280/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-16%20174104.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;可以看到有scan 到0x48這個位址, 這就是TMP102的I2C slave address. 如此就成功了, 基本上硬體已經被認到了。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;接下來, 照著前面提到的文章的作法做:&lt;/div&gt;&lt;div&gt;$&amp;nbsp;echo tmp102 0x48 &amp;gt; /sys/class/i2c-adapter/i2c-1/new_device&lt;/div&gt;&lt;div&gt;結果出現錯誤訊息, 基本上沒有寫入的權限! 用ls -l 指令查看此檔, 發現預設只有root才有寫入的權限, 但即使在echo 之前加入sudo, 也沒用! 後來用以下指令解決:&lt;/div&gt;&lt;div&gt;$ sudo chmod 666 /sys/class/i2c-adapter/i2c-1/new_device&lt;/div&gt;&lt;div&gt;然後再下:&lt;/div&gt;&lt;div&gt;$&amp;nbsp;echo tmp102 0x48 &amp;gt; /sys/class/i2c-adapter/i2c-1/new_device&lt;/div&gt;&lt;div&gt;就可以了!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;現在可以使用sensors指令:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1LSKtD2PLTRIi2r2eBrKtGOfBv-8QNnfKbxpZhaILi6NI4357NsmfaVYKFG3ERCUKJpPT0Anta3xFkj8_ecyZJSQM3dF7uBDTCeyCVDSqa9mgsnwEqUr0vNkucERGnrlk6-xeWANOqihx8Z6Zm91QrKVKW3Pm94__W8krhORkQRSVAMza6PkwgZ3XG2s/s1083/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-16%20175534.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;512&quot; data-original-width=&quot;1083&quot; height=&quot;302&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1LSKtD2PLTRIi2r2eBrKtGOfBv-8QNnfKbxpZhaILi6NI4357NsmfaVYKFG3ERCUKJpPT0Anta3xFkj8_ecyZJSQM3dF7uBDTCeyCVDSqa9mgsnwEqUr0vNkucERGnrlk6-xeWANOqihx8Z6Zm91QrKVKW3Pm94__W8krhORkQRSVAMza6PkwgZ3XG2s/w640-h302/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-16%20175534.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;可以看到除了原來CPU的温度(上圖的30.7 C)外, 多出了一個tmp102-i2c-1-48的温度(上圖的24.7 C)。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;但是此時下i2cdetect -y 1指令, 會發現原來的48變成UU, 也就是被系統使用! 此時, 你如果使用Python程式去取得TMP102的温度值, 會發現出現資源被佔用的錯誤。即使你把TMP102拔走, 再插回來, 也沒有用!&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRJi3cH3BuH0Aw_IcIZpp1iy8tN6hczYDuFWopc44BlPE3C9WbvnXU0eo6EyqxeWT8H2IrQLa8ajFbQGRDLHLp3fqLfmdP9TdSSgnIgnOwiVGnln6FC-wSl34acCkgGmRE6v4YSAiJ5c6W4_0309-rQbx1PM0vs-GaAoCOv0-hMj4UsdfxSotPmpKqEew/s1095/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-17%20090530.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;525&quot; data-original-width=&quot;1095&quot; height=&quot;306&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRJi3cH3BuH0Aw_IcIZpp1iy8tN6hczYDuFWopc44BlPE3C9WbvnXU0eo6EyqxeWT8H2IrQLa8ajFbQGRDLHLp3fqLfmdP9TdSSgnIgnOwiVGnln6FC-wSl34acCkgGmRE6v4YSAiJ5c6W4_0309-rQbx1PM0vs-GaAoCOv0-hMj4UsdfxSotPmpKqEew/w640-h306/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-17%20090530.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;解決方法, 就是下指令把它移除:&lt;/div&gt;&lt;div&gt;$ sudo chmod 666 /sys/class/i2c-adapter/i2c-1/delete_device&lt;/div&gt;&lt;div&gt;$ echo 0x48 &amp;gt; /sys/class/i2c-adapter/i2c-1/delete_device&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(這裡我google不到有人提到應該怎麼做，但我想應該和加入新設備的方式差不多，所以嘗試可能的指令後試出來的!&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5rmcM4i1HKt4P87QF5I8ToOjUcvLvWapU1VJre-NpifTRVVOC0r-9M_Vkg96MrwWikmrgiADYBCU27KL45iGMheIJdW1AWiSp91Lvuqw_n0vt5TJbVrKTidTgOH-wPJqecbgi3umxea730Qv4ni4ByOuZD-FvPj-UDmPi5tBe0yiPW4RZx-Ss405LC_c/s1081/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-17%20155039.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;344&quot; data-original-width=&quot;1081&quot; height=&quot;204&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5rmcM4i1HKt4P87QF5I8ToOjUcvLvWapU1VJre-NpifTRVVOC0r-9M_Vkg96MrwWikmrgiADYBCU27KL45iGMheIJdW1AWiSp91Lvuqw_n0vt5TJbVrKTidTgOH-wPJqecbgi3umxea730Qv4ni4ByOuZD-FvPj-UDmPi5tBe0yiPW4RZx-Ss405LC_c/w640-h204/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-17%20155039.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;圖中圈起來部份, 就是錯誤嘗試的部份! )&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;這樣, 再下i2cdetect -y 1指令, 或sensors指令, 就會看到沒有加入TMP102 sensor之前的狀態。此時用Python程式去讀TMP102温度值, 也會正常。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;以下Python程式, 由&lt;a href=&quot;http://www.pibits.net/amp/code/tmp102-sensor-and-raspberry-pi-python-example.php&quot; target=&quot;_blank&quot;&gt;TMP102 sensor and Raspberry Pi python example&lt;/a&gt;貼文取得, 可讀取TMP102温度值, 原貼文格式和一些文字亂掉, 在此有做一些修正。(註:後來發現，這支Python程式在SparkFun文章:&lt;a href=&quot;https://learn.sparkfun.com/tutorials/python-programming-tutorial-getting-started-with-the-raspberry-pi/experiment-4-i2c-temperature-sensor&quot; target=&quot;_blank&quot;&gt;Python Programming Tutorial: Getting Started with the Raspberry Pi&lt;/a&gt;就有一模一樣的, 真是天下文章一大抄!)&lt;/div&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;
import time
import smbus

i2c_ch = 1

# TMP102 address on the I2C bus
i2c_address = 0x48

# Register addresses
reg_temp = 0x00
reg_config = 0x01

# Calculate the 2’s complement of a number
def twos_comp(val, bits):
&amp;nbsp; &amp;nbsp; if (val &amp;amp; (1 &amp;lt;&amp;lt; (bits - 1))) != 0:
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; val = val - (1 &amp;lt;&amp;lt; bits)
&amp;nbsp; &amp;nbsp; return val

# Read temperature registers and calculate Celsius
def read_temp():
&amp;nbsp; &amp;nbsp; # Read temperature registers
&amp;nbsp; &amp;nbsp; val = bus.read_i2c_block_data(i2c_address, reg_temp, 2)
&amp;nbsp; &amp;nbsp; temp_c = (val[0] &amp;lt;&amp;lt; 4) | (val[1] &amp;gt;&amp;gt; 5)

&amp;nbsp; &amp;nbsp; # Convert to 2s complement (temperatures can be negative)
&amp;nbsp; &amp;nbsp; temp_c = twos_comp(temp_c, 12)

&amp;nbsp; &amp;nbsp; # Convert registers value to temperature (C)
&amp;nbsp; &amp;nbsp; temp_c = temp_c * 0.0625

&amp;nbsp; &amp;nbsp; return temp_c

# Initialize I2C (SMBus)
bus = smbus.SMBus(i2c_ch)

# Read the CONFIG register (2 bytes)
val = bus.read_i2c_block_data(i2c_address, reg_config, 2)
print(&quot;Old CONFIG:&quot;, val)

# Set to 4 Hz sampling (CR1, CR0 = 0b10)
val[1] = val[1] &amp;amp; 0b00111111
val[1] = val[1] | (0b10 &amp;lt;&amp;lt; 6)

# Write 4 Hz sampling back to CONFIG
bus.write_i2c_block_data(i2c_address, reg_config, val)

# Read CONFIG to verify that we changed it
val = bus.read_i2c_block_data(i2c_address, reg_config, 2)
print(&quot;New CONFIG:&quot;, val)

# Print out temperature every second
while True:
&amp;nbsp; &amp;nbsp; temperature = read_temp()
&amp;nbsp; &amp;nbsp; print(round(temperature, 2), &quot;C&quot;)
&amp;nbsp; &amp;nbsp; time.sleep(1)
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
為什麼自已寫Python程式讀取TMP102的温度值要寫這麼多代碼? 但用sensors指令, 卻只要找到I2C slave address並寫入/sys/class/i2c-adapter/i2c-1/new_device這個特定的檔案, 然後sensors指令就可以正確的解讀出温度值來呢?&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;一定有小精靈在背後幫忙做這個換算的工作, 否則sensors指令怎麼知道要讀取那個暫存器, 然後要左移或右移幾位, 接著還要做2的補數, 再乘以某個數呢? 這個小精靈就是Kernel space driver for TMP102!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;反過來說, 我拿BOSCH BME280感測器, 同樣以I2C接線方式連接, 再下i2cdetect -y 1, 也可以看到有scan到0x76這個位址。那麼依照上文所提方法, 下指令:&lt;/div&gt;&lt;div&gt;$ echo bme280 0x76 &amp;gt; /sys/class/i2c-adapter/i2c-1/new_device&lt;/div&gt;&lt;div&gt;是成功了, 沒有錯誤訊息! 但下sensors指令, 卻沒看到有多出bme280的數值!&lt;/div&gt;&lt;div&gt;下lsmod查看:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNVdmmsokbPaJ1eLelsWR3-lGnB2pIfOo2OWZTGxIVYwQifNL4-H74hhoqLbVcF8klqaQMJj4CFw8yLs-xX_HJLNT4iomzOKcpPBh5fm8jImjZtIhbwRDhLHvuwSm3eVZ-RlArLMadOrzAXPkEsOx_HPJJV6fIxJ_p8IhvWWa9Hkuq06Z6HK9olDntXEY/s1090/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-18%20091221.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;548&quot; data-original-width=&quot;1090&quot; height=&quot;322&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNVdmmsokbPaJ1eLelsWR3-lGnB2pIfOo2OWZTGxIVYwQifNL4-H74hhoqLbVcF8klqaQMJj4CFw8yLs-xX_HJLNT4iomzOKcpPBh5fm8jImjZtIhbwRDhLHvuwSm3eVZ-RlArLMadOrzAXPkEsOx_HPJJV6fIxJ_p8IhvWWa9Hkuq06Z6HK9olDntXEY/w640-h322/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-18%20091221.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;圖中圈起來部份, 顯示系統有抓到裝置, 但是卻將之視為BMP280, 這一顆只有壓力和温度感測沒有溼度, 而且顯然和BME280不太相容! 所以系統讀不到數值。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;那麼如果就是想使用BME280, 然後要讓sensors指令可以讀到它的數值呢? 烏克蘭朋友Eduard Malokhvii, 為BME280寫了Kernel space driver, 有興趣的朋友可以試試:&amp;nbsp;&lt;a href=&quot;https://github.com/malokhvii-eduard/lkmod-bme280&quot; target=&quot;_blank&quot;&gt;Kernel space driver for Bosch Sensortec BME280&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/8531364829517007421/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/8531364829517007421?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/8531364829517007421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/8531364829517007421'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2023/08/how-to-add-tmp102-sensor-to-raspberry.html' title='How to add (and remove) Tmp102 sensor to Raspberry Pi 4'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX4qTxnxVV13jipS38zrfSJ-jclSUIeXhnVMaOZ0JvsFR4_8Al9sBqHiRQMYEeUzzAFCgB6tz1JtyugqVNV6u8zBpHyZE7fBd2aLEl5OM9HqTR5rx_5MeIokwGlCcsyhJPro4W3DFhQNMxc-p9y2FbB3PGtWUvP86qoeQp0REQzJkzkryH2wjfrL4fWCc/s72-w640-h446-c/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-08-17%20085538.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-4588888192635233112</id><published>2023-08-08T10:50:00.009+08:00</published><updated>2023-08-08T11:29:24.111+08:00</updated><title type='text'>reject=403 4.7.0 TLS handshake failed (2)</title><content type='html'>&lt;p&gt;&amp;nbsp;reject=403 4.7.0 TLS handshake failed&lt;/p&gt;&lt;p&gt;這個訊息總是會出現在我們sendmail的log檔, 之前找到msn.com網域的信, 其實是寄到outlook.com網域去的。這次是另一個類似的案例:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;
&lt;p&gt;# mailq&lt;/p&gt;&lt;p&gt;Warning: Option: AuthMechanisms requires SASL support (-DSASL)&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; /var/spool/mqueue (1 request)&lt;/p&gt;&lt;p&gt;-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------&lt;/p&gt;&lt;p&gt;3781ZYIW045303&amp;nbsp; &amp;nbsp;164044 Tue Aug&amp;nbsp; 8 09:35 &amp;lt;&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;(Deferred: 403 4.7.0 TLS handshake failed.)&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;lt;bounce-833_HTML-127233725-9424761-700&lt;/p&gt;&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Total requests: 1&lt;/p&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在mailq裡面看到一封寄不出去的信, 之前查過, 知道這應該是寄到我們合法使用者的廣告信, 收到使用者信箱後, 自動彈回的收到回條! (bounce-xxx...) 我們要求sendmail自動重送queue裡的信, 來看看問題何在?&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;
# sendmail -v -q
Warning: Option: AuthMechanisms requires SASL support (-DSASL)

Running /var/spool/mqueue/3781ZYIW045303 (sequence 1 of 1)
&amp;lt;bounce-833_HTML-127233725-9424761-7002400-1004@bounce.email.savills-asia.com&amp;gt;... Connecting to inbound.s6.exacttarget.com. via esmtp...
220 orionsmtp-172.s6.exacttarget.com ESMTP Postfix
&amp;gt;&amp;gt;&amp;gt; EHLO mail1.princo.com.tw
250-orionsmtp-172.s6.exacttarget.com
250-PIPELINING
250-SIZE 10240000
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
&amp;gt;&amp;gt;&amp;gt; STARTTLS
220 2.0.0 Ready to start TLS
&amp;lt;bounce-833_HTML-127233725-9424761-7002400-1004@bounce.email.savills-asia.com&amp;gt;... Deferred: Name server: inbound.s6.exacttarget.com.: host name lookup failure
Closing connection to inbound.s6.exacttarget.com.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到這封要寄到xx@bounce.email.savills-asia.com的信, 居然是傳到xx.exacttarget.com的郵件主機去! 那因為這台郵件主機回應了250-STARTTLS, 所以我們sendmail就下了STARTTLS命令, 要求進入加密通道, 但接著就出現了錯誤訊息:&amp;nbsp;Name server: inbound.s6.exacttarget.com.: host name lookup failure。那是誰的主機名稱沒有設好呢? 我試著用nslookup找了一下:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;
# nslookup
&amp;gt; bounce.email.savills-asia.com
Server:         10.1.10.8
Address:        10.1.10.8#53

Non-authoritative answer:
*** Can&amp;acute;t find bounce.email.savills-asia.com: No answer
&amp;gt; savills-asia.com
;; Got recursion not available from 10.1.10.8, trying next server
;; Got recursion not available from 10.1.10.101, trying next server
Server:         168.95.1.1
Address:        168.95.1.1#53

Non-authoritative answer:
Name:   savills-asia.com
Address: 217.19.248.132
&amp;gt; inbound.s6.exacttarget.com.
Server:         10.1.10.8
Address:        10.1.10.8#53

Non-authoritative answer:
Name:   inbound.s6.exacttarget.com
Address: 68.232.203.116
&amp;gt; exit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;確實bounce.email.savills-asia.com是查不到對應ip的, 看起來不像是我們的設定或軟體版本有問題! 所以, 我就將exacttarget.com在/etc/mail/access檔案裡, 設為不使用TLS. (Try_TLS:exacttarget.com NO 以及 tls_srv:exacttarget.com NO) 然後再來試試重送一次郵件:
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;
# mailq
Warning: Option: AuthMechanisms requires SASL support (-DSASL)
                /var/spool/mqueue (1 request)
-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------
3781ZYIW045303   164044 Tue Aug  8 09:35 &amp;lt;&amp;gt;
                 (Deferred: 403 4.7.0 TLS handshake failed.)
                                         &amp;lt;bounce-833_HTML-127233725-9424761-700
                Total requests: 1
mail1# sendmail -v -q
Warning: Option: AuthMechanisms requires SASL support (-DSASL)

Running /var/spool/mqueue/3781ZYIW045303 (sequence 1 of 1)
&amp;lt;bounce-833_HTML-127233725-9424761-7002400-1004@bounce.email.savills-asia.com&amp;gt;... Connecting to inbound.s6.exacttarget.com. via esmtp...
220 orionsmtp-55.s6.exacttarget.com ESMTP Postfix
&amp;gt;&amp;gt;&amp;gt; EHLO mail1.princo.com.tw
250-orionsmtp-55.s6.exacttarget.com
250-PIPELINING
250-SIZE 10240000
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
&amp;gt;&amp;gt;&amp;gt; MAIL From:&amp;lt;&amp;gt; SIZE=165559
250 2.1.0 Ok
&amp;gt;&amp;gt;&amp;gt; RCPT To:&amp;lt;bounce-833_HTML-127233725-9424761-7002400-1004@bounce.email.savills-asia.com&amp;gt;
&amp;gt;&amp;gt;&amp;gt; DATA
250 2.1.5 Ok
354 End data with &amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;.&amp;lt;CR&amp;gt;&amp;lt;LF&amp;gt;
&amp;gt;&amp;gt;&amp;gt; .
250 2.0.0 Ok: queued as 27DE514004F
&amp;lt;bounce-833_HTML-127233725-9424761-7002400-1004@bounce.email.savills-asia.com&amp;gt;... Sent (Ok: queued as 27DE514004F)
Closing connection to inbound.s6.exacttarget.com.
&amp;gt;&amp;gt;&amp;gt; QUIT
221 2.0.0 Bye
mail1# mailq
Warning: Option: AuthMechanisms requires SASL support (-DSASL)
/var/spool/mqueue is empty
                Total requests: 0

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到, 這樣就把信寄過去了, 所以到底是什麼問題? 用TLS加密通道, 對方就會回主機名稱找不到, (但我看不出來到底是那個主機名稱找不到!)不用TLS, 那就正常. 總之, 由mailq來看問題, 再由sendmail -v -q重現狀況, 提供了一個不錯的除錯方式。
&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/4588888192635233112/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/4588888192635233112?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/4588888192635233112'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/4588888192635233112'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2023/08/reject403-470-tls-handshake-failed-2.html' title='reject=403 4.7.0 TLS handshake failed (2)'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-4802510699173304412</id><published>2023-07-11T10:35:00.007+08:00</published><updated>2023-07-11T10:56:07.468+08:00</updated><title type='text'>超簡單做出低功耗藍牙温度計-Part 3(nRF52840 Dongle + BME280 + CircuitPython)</title><content type='html'>&lt;p&gt;&amp;nbsp;之前用TMP102, 只有温度值可以看, 若加上溼度值, 會更具實用性! 那就要改用別顆感測器了, 具温溼度感測功能的sensor有很多選擇, 之前試了DHT11, AM2320, BME280, 覺得BOSCH BME280比較好用, 晶片本身具有I2C, SPI界面, 有些模塊二個界面都有把pin腳引出, 有些模塊只引出I2C, 這種的價錢便宜許多。這裡, 只使用I2C, 所以寫程式方式和之前(TMP102)文章相似, 也可以使用便宜的模塊就好。&lt;/p&gt;&lt;p&gt;同Part 2的文章, 使用CircuitPython來實作BLE低功耗藍牙傳輸資料, 可以使用Adafruit寫好的Bluefruit Connect App, 我們只要在nRF52840 Dongle上面透過現成的BLE UART服務, 把温度和溼度的數值傳送出去給App就可以了。先看一下完成的樣子:&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQbmRTeFNZ1GMWfcdRoVd1wppT65fmQRbx3u4gPtPyr9Sa9iMAkgKtiVQPcJq4kS_VEeykre7X9mf_pHb69ONvJjasVhfUn-KH8aCRLU9JtS7RrhK7xts3QEI8SpCi04eHCzLpVz3_nZYNJcMHtA4fzZbAl82JMjNRRYCaiaqF5umCgVSxc6uDAk355tY/s2208/IMG_2507.PNG&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;2208&quot; data-original-width=&quot;1242&quot; height=&quot;640&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQbmRTeFNZ1GMWfcdRoVd1wppT65fmQRbx3u4gPtPyr9Sa9iMAkgKtiVQPcJq4kS_VEeykre7X9mf_pHb69ONvJjasVhfUn-KH8aCRLU9JtS7RrhK7xts3QEI8SpCi04eHCzLpVz3_nZYNJcMHtA4fzZbAl82JMjNRRYCaiaqF5umCgVSxc6uDAk355tY/w360-h640/IMG_2507.PNG&quot; width=&quot;360&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5a1ucDt6GWcoOdNkUe5KE_06O_mRZhK3nQKc9HOSiumNSfZ-xqIfv5uwcqaTiozuCT0aqmrNMOH9N1EX5mngRJiQDRJHZCJo6dFMqIpGig3o3VgaEEdq0dRFa-97O6v4AXJUjUxFceNad4t1vhJq9gerYsu1Ur6xtrKgZOPNJeFWCIkDEzaneFnBGeJQ/s2208/IMG_2506.PNG&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;2208&quot; data-original-width=&quot;1242&quot; height=&quot;640&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5a1ucDt6GWcoOdNkUe5KE_06O_mRZhK3nQKc9HOSiumNSfZ-xqIfv5uwcqaTiozuCT0aqmrNMOH9N1EX5mngRJiQDRJHZCJo6dFMqIpGig3o3VgaEEdq0dRFa-97O6v4AXJUjUxFceNad4t1vhJq9gerYsu1Ur6xtrKgZOPNJeFWCIkDEzaneFnBGeJQ/w360-h640/IMG_2506.PNG&quot; width=&quot;360&quot; /&gt;&lt;/a&gt;&lt;/div&gt;送出來的資料格式就是温度值接著是逗號, 然後是溼度值再接著換行符號。這樣在Plotter就會出現2條線, 一條代表温度, 一條代表溼度。&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;因為BLE UART服務的寫法, 之前的文章已經看過, 我們現在只要克服讀取BME280這個問題就好了。之前在使用TMP102的時候, 提過可以使用別人現成寫好的驅動, 但為了更深入掌握TMP102, 之前的文章有去了解驅動的寫法, 而且我們自己也動手寫了一支適合自己的TMP102驅動。但這其實很花時間! 在這裡, 我們直接使用現成的BME280驅動。一樣去CircuitPython Librarys (adafruit cricuitpython bundle)找就有 (adafruit_bme280), 如下圖, 把這個目錄複製到開發板上的lib目錄下面:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-WaKnrlRPEf8OkceDzZHHYznnXtm7MBAq3FrhMXwOqUyo6W_qm_ELHOdbJzrgnN-R4Hn9dzghjtnNPIMSxhGSYx6OAcCv5arP_ZNVZPhiUAkE-tZFXKZocxbid9UY3IEDweZG4-gs_yf1WRmgXJhpPwzFC-GPhnz39oC2vUyxY6VpJRNlmmanRG9Q8vA/s800/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-07-09%20125250.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;495&quot; data-original-width=&quot;800&quot; height=&quot;396&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-WaKnrlRPEf8OkceDzZHHYznnXtm7MBAq3FrhMXwOqUyo6W_qm_ELHOdbJzrgnN-R4Hn9dzghjtnNPIMSxhGSYx6OAcCv5arP_ZNVZPhiUAkE-tZFXKZocxbid9UY3IEDweZG4-gs_yf1WRmgXJhpPwzFC-GPhnz39oC2vUyxY6VpJRNlmmanRG9Q8vA/w640-h396/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-07-09%20125250.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;我買的BME280, 如下圖, 只用到左邊4支接腳(VCC, GND, SCL, SDA)。&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpT9eAYWL2cG3Mr3wnagV6xg4Qb2cU8ANULVLI86cDQZUvvpqlWV4DrR55XzNvV41NUlDpXoYJJBOti4AtHLkbvIpFgU_PT3rfEGk1xljrS3SMehpR_SNBvMGxnEGG68Kqh7ME76udB114htAe090G1JBjhzIuqs6kPgrTxoPg_jSyp51OGgNnHCslnZk/s1200/71Ez2hjcSoL._SL1200_.jpg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1200&quot; data-original-width=&quot;1200&quot; height=&quot;200&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpT9eAYWL2cG3Mr3wnagV6xg4Qb2cU8ANULVLI86cDQZUvvpqlWV4DrR55XzNvV41NUlDpXoYJJBOti4AtHLkbvIpFgU_PT3rfEGk1xljrS3SMehpR_SNBvMGxnEGG68Kqh7ME76udB114htAe090G1JBjhzIuqs6kPgrTxoPg_jSyp51OGgNnHCslnZk/w200-h200/71Ez2hjcSoL._SL1200_.jpg&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;同樣接到nRF52840 Dongle的(VDD OUT, GND, 0.31, 0.29), 如下圖圈起處:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQkJusfK9PAYip3LCjRAkBSsXCyaWG2CmkiugGb1VGcggalSPOMrx7O6tUghN5gsLbOwBGfI6Y2EjkANd4WBWFaIfy3RyCTEX2qNmWG8t_kA-htC24uOmThS3YUQU-zeI8_m0gkYuuq6KBArPVCrwHzF8sd3GyVUb-iNm0iPKnegcwIMSTxGb7Gcar818/s744/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-07-11%20103134.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;317&quot; data-original-width=&quot;744&quot; height=&quot;272&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQkJusfK9PAYip3LCjRAkBSsXCyaWG2CmkiugGb1VGcggalSPOMrx7O6tUghN5gsLbOwBGfI6Y2EjkANd4WBWFaIfy3RyCTEX2qNmWG8t_kA-htC24uOmThS3YUQU-zeI8_m0gkYuuq6KBArPVCrwHzF8sd3GyVUb-iNm0iPKnegcwIMSTxGb7Gcar818/w640-h272/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-07-11%20103134.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;把下面程式存入至Dongle上面的code.py, Ctr-D, 同樣由終端機來觀察看看, 如果都成功取得數值, 那麼就成功連通BME280了。&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;py&quot;&gt;import time
import board
import busio
from adafruit_bme280 import basic as adafruit_bme280

i2c = busio.I2C(board.P0_31, board.P0_29)
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c, 0x76)

# change this to match the location&#39;s pressure (hPa) at sea level
bme280.sea_level_pressure = 1013.25

while True:
    print(&quot;\nTemperature: %0.1f C&quot; % bme280.temperature)
    print(&quot;Humidity: %0.1f %%&quot; % bme280.relative_humidity)
    print(&quot;Pressure: %0.1f hPa&quot; % bme280.pressure)
    print(&quot;Altitude = %0.2f meters&quot; % bme280.altitude)
    time.sleep(2)
&lt;/code&gt;&lt;/pre&gt;
這段程式裡, BME280的I2C設備位址必須指明為0x76, 如果不指定, 預設為0x77。我買的這顆BME280模塊可以由SDO腳位來決定其I2C設備位址, SDO為high時位址為0x77, 否則為0x76。為了線路簡化, 就使用0x76位址吧!&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;接著把以下程式放到Dongle的code.py, 同樣重開機, 就可以打開手機Bluefruit connect App來查看温溼度的數值了。&lt;/div&gt;&lt;div&gt;簡單吧! 只要接對線, 複製現成的驅動, 加上以下現成程式, 就完成了。&lt;/div&gt;

&lt;pre&gt;&lt;code class=&quot;py&quot;&gt;
# CircuitPython Bluefruit LE Connect Plotter Example

import time
import board
import busio
from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService

from adafruit_bme280 import basic as adafruit_bme280
i2c = busio.I2C(board.P0_31, board.P0_29)
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c, 0x76)

ble = BLERadio()
uart_server = UARTService()
advertisement = ProvideServicesAdvertisement(uart_server)


while True:
    # Advertise when not connected.
    ble.start_advertising(advertisement)
    while not ble.connected:
        pass
    ble.stop_advertising()

    while ble.connected:
        tempc = bme280.temperature
        humidity = bme280.relative_humidity
        print(&quot;{}, {}&quot;.format(tempc, humidity))
        uart_server.write(&quot;{}, {}\n&quot;.format(tempc, humidity))
        time.sleep(2.0) 
&lt;/code&gt;&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/4802510699173304412/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/4802510699173304412?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/4802510699173304412'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/4802510699173304412'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2023/07/part-3nrf52840-dongle-bme280.html' title='超簡單做出低功耗藍牙温度計-Part 3(nRF52840 Dongle + BME280 + CircuitPython)'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQbmRTeFNZ1GMWfcdRoVd1wppT65fmQRbx3u4gPtPyr9Sa9iMAkgKtiVQPcJq4kS_VEeykre7X9mf_pHb69ONvJjasVhfUn-KH8aCRLU9JtS7RrhK7xts3QEI8SpCi04eHCzLpVz3_nZYNJcMHtA4fzZbAl82JMjNRRYCaiaqF5umCgVSxc6uDAk355tY/s72-w360-h640-c/IMG_2507.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-419221146276313348</id><published>2023-07-09T11:53:00.015+08:00</published><updated>2023-07-09T13:45:03.248+08:00</updated><title type='text'>超簡單做出低功耗藍牙温度計-Part 2(nRF52840 Dongle + TMP102 + CircuitPython)</title><content type='html'>&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjQLjui6VgTlSYo1EI1dxWkmF8tAs_6m3pH_dkela9vH-miNhupTL4BQ_Ofxj2Dh-5akEzjV_hn8Xoa40IvazyJwV0LU5RapBvDWssuhBuvmywi3TzhQq6z_Av072SXIUHQihCzuUhGF8bZxcGQnhUkLGh6ZKwDeCC6a9KAtjamVKbX-wV7XcIQ5nO4j0/s1585/2902521-40.jpg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;582&quot; data-original-width=&quot;1585&quot; height=&quot;118&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjQLjui6VgTlSYo1EI1dxWkmF8tAs_6m3pH_dkela9vH-miNhupTL4BQ_Ofxj2Dh-5akEzjV_hn8Xoa40IvazyJwV0LU5RapBvDWssuhBuvmywi3TzhQq6z_Av072SXIUHQihCzuUhGF8bZxcGQnhUkLGh6ZKwDeCC6a9KAtjamVKbX-wV7XcIQ5nO4j0/s320/2902521-40.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;同樣都使用nRF52840 Dongle, 上一次是用MicroPython, 這一次來用用CircuitPython。不管怎麼說, CircuitPython有Adafruit在支持, 文件和資源是更多的。而且, 目前CircuitPython支持的MCU就是以SAMD21/51和nRF系列為主。但要讓nRF52840 Dongle可以跑CircuitPython, 我們要先做些工作, 網路上有2個地方可以參考, 第1個是這篇文章,&amp;nbsp;&lt;a class=&quot;af ag ah ai aj ak al am an ao ap aq ar gt&quot; href=&quot;https://pietrowicz-eric.medium.com/?source=post_page-----80a7d3a88954--------------------------------&quot; rel=&quot;noopener follow&quot; style=&quot;-webkit-tap-highlight-color: transparent; background-color: white; border: inherit; box-sizing: inherit; cursor: pointer; fill: inherit; font-family: inherit; font-size: inherit; font-weight: inherit; letter-spacing: inherit; margin: 0px; padding: 0px; text-decoration-line: none;&quot;&gt;Eric Pietrowicz&lt;/a&gt;使用PCA10056開發板上的JLink除錯器來燒錄具UF2功能的Bootloader。&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://pietrowicz-eric.medium.com/circuit-python-on-nrf52840-usb-dongle-with-jlink-80a7d3a88954&quot; target=&quot;_blank&quot;&gt;Bluetooth Low Energy with CircuitPython on a nRF52840 USB Dongle&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;第2個是這個影片, rdagger使用的是OpenOCD除錯器配合Raspberry Pi 3B來燒錄具UF2功能的Bootloader到nRF52840 Dongle。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;iframe allowfullscreen=&quot;&quot; class=&quot;BLOG_video_class&quot; height=&quot;266&quot; src=&quot;https://www.youtube.com/embed/R5wub5ywzTU&quot; width=&quot;320&quot; youtube-src-id=&quot;R5wub5ywzTU&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;當然, 直接使用JLink來燒錄也是可以。&lt;/p&gt;&lt;p&gt;具UF2功能的Bootloader是CircuitPython開發板的標配, 這個Bootloader讓開發板一插到電腦USB, 就會出現一個小硬碟, 讓你感覺這個開發板就是一個小磁碟機, 接下來我們要燒錄firmware, 就只要直接拖拉firmware檔案進去就可以了。&lt;/p&gt;&lt;p&gt;nRF52840 Dongle的UF2 Bootloader, 以及其CircuitPython firmware可以在以下連結找到&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://circuitpython.org/board/pca10059/&quot; target=&quot;_blank&quot;&gt;https://circuitpython.org/board/pca10059/&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;依照前面提到的文章說明, 把nRF52840 Dongle的Bootloader燒成具UF2功能的, 之後插入這支Dongle到電腦的USB埠, 就會出現一個名為NRF52BOOT之類的小磁碟機, 然後將CircuitPython的.uf2 firmware拖拉進去, 就會打造出一個跑CircuitPython的開發板了。&lt;/p&gt;&lt;p&gt;這個過程需要一些工作, 如果覺得太累, 也可以買一個出廠就已經幫你燒好UF2 Bootloader的開發板,&amp;nbsp;&lt;a href=&quot;https://www.adafruit.com/product/4062&quot; target=&quot;_blank&quot;&gt;Adafruit Feather nRF52840 Express&lt;/a&gt;就是一個, S&lt;span face=&quot;Roboto, &amp;quot;Noto Sans&amp;quot;, Arial, Helvetica, sans-serif, dk&quot; style=&quot;background-color: white; color: #444444; font-size: 12px;&quot;&gt;EEED STUDIO XIAO NRF52840&lt;/span&gt;也是。&lt;/p&gt;&lt;p&gt;燒好CircuitPython firmware後, 插入nRF52840 Dongle, 就會看到出現一個名為CIRCUITPY的小磁碟機:&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxf1sJI-g1a3Jy5Y3Raw63Y-F1G4bTrNadNTDGG9-uBR6IWOP98GJ0ST-FFArCAYPwDBr7k32GGhiyO2Je4CSYdbGqZIbvupHHm5Y3OzehX_XM1l-OXq52sAVzksnJlvwkw9FmN_LEAaDe5MOhjP7RhofJog-nS9s2Nm3BnzxLcwOoQo5j75tOELvrKuY/s897/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-07-09%20112357.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;555&quot; data-original-width=&quot;897&quot; height=&quot;396&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxf1sJI-g1a3Jy5Y3Raw63Y-F1G4bTrNadNTDGG9-uBR6IWOP98GJ0ST-FFArCAYPwDBr7k32GGhiyO2Je4CSYdbGqZIbvupHHm5Y3OzehX_XM1l-OXq52sAVzksnJlvwkw9FmN_LEAaDe5MOhjP7RhofJog-nS9s2Nm3BnzxLcwOoQo5j75tOELvrKuY/w640-h396/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-07-09%20112357.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisHvb_s6nPookFH8F5xiilFDbRjiclPRmj_f8VyS-nG-dgOWuq31BnwyhW8sk2Tos4ZOlJvsUgfSyURG1JIBPvUAK6AiNB0bvM2s91m_hzhnGoX23Ma-h7Gmshz5m7NvoQJdyECsfUpqlTZN9uLnCEjov59Ow5HC6pqb1wyU6FbKHdH0bvGRfZld3YA14/s897/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-07-09%20112812.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;555&quot; data-original-width=&quot;897&quot; height=&quot;396&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisHvb_s6nPookFH8F5xiilFDbRjiclPRmj_f8VyS-nG-dgOWuq31BnwyhW8sk2Tos4ZOlJvsUgfSyURG1JIBPvUAK6AiNB0bvM2s91m_hzhnGoX23Ma-h7Gmshz5m7NvoQJdyECsfUpqlTZN9uLnCEjov59Ow5HC6pqb1wyU6FbKHdH0bvGRfZld3YA14/w640-h396/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-07-09%20112812.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;其中有一個名為lib的目錄, 是用來放硬體驅動的, 而code.py是一開機就會執行的python程式。為了讀取TMP102温度的數值, 同樣我們需要一支驅動程式, 這可以使用我們&lt;a href=&quot;https://ops9.blogspot.com/2023/06/nrf52840-dongle-tmp102-mircopython.html&quot; target=&quot;_blank&quot;&gt;先前那篇文章&lt;/a&gt;的那支驅動來修改。啊! 同樣都是Python, MicroPython和CircuitPython也會有不同哦!&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJ97XmYWysxDrw59uxkLPxlm3O4C_RLkwVymfwHVZ_iTStK5zULZbce87GMITKu_LwhdCgdTdRfL4t0cJC4rC_8KFuUEa2O02Rv2Qtdlz2U3cq_n_nv1yf-Omg9aYblNel2lDvkBL-43ChrIlanHz3-MNTpKECXyvVNsfKoTcABTOpYPcswl-53hKLzlo/s1086/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-07-09%20115235.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;785&quot; data-original-width=&quot;1086&quot; height=&quot;462&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJ97XmYWysxDrw59uxkLPxlm3O4C_RLkwVymfwHVZ_iTStK5zULZbce87GMITKu_LwhdCgdTdRfL4t0cJC4rC_8KFuUEa2O02Rv2Qtdlz2U3cq_n_nv1yf-Omg9aYblNel2lDvkBL-43ChrIlanHz3-MNTpKECXyvVNsfKoTcABTOpYPcswl-53hKLzlo/w640-h462/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-07-09%20115235.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;好在, 要改的也不多, 如上圖, 把_read_register()這個函數小改一下, 就可以了。這樣我們就有一個可以在CircuitPython使用的TMP102驅動。同樣把這個驅動命名為tmp102.py, 然後copy到CIRCUITPY這個磁碟的lib目錄去。不過, 因為空間和效率的考量, 通常會使用mpy-cross工具, 將.py轉成.mpy的格式。&lt;br /&gt;&lt;p&gt;接下來, 試試用用這支驅動來讀讀温度吧!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;py&quot;&gt;
from tmp102 import Tmp102
import board
import busio
import time

i2c = busio.I2C(board.P0_29, board.P0_31)
sensor = Tmp102(i2c, 0x48)


# periodic read
i2c.try_lock() 
sensor.wakeup()
print(sensor.get_TempC(sensor.temperature()))
i2c.unlock()

# one-shot read
i2c.try_lock()
sensor.sleep()

run = True
while run:
    try:
        sensor.set_one_shot()
        print(sensor.get_TempC(sensor.get_one_shot()))
        time.sleep(1.0)
    except:
        run = False

i2c.unlock()&lt;/code&gt;&lt;/pre&gt;
這裡可以看到CircuitPython的寫法還是和MicroPython有一些小差異的! 我們在此使用busio來將I2C設置起來也是nRF52840這顆MCU特定的。在此, 我將pin 0.29指定為SCL, pin 0.31指定為SDA, 所以在硬體接線時, 也要如此接。把上面這個程式存到CIRCUITPY這個磁碟的code.py檔案, 打開終端機, 觀察:&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvmy8pEjhOWL78XzHX_fhw-VK3l4qsFxlq8hI-ECbiwuPQznL6o8oAxlq9EBRIjdRLkauv6HauJesobBlNAS8xzFyH6V78F3KthrL3z1f2YvqgwgBfCFXVWmMXt1ER1J8fySc0nj3Mk_0FOP9QLySmQrlYxf0oWll0b6fFlCSl86lgSEQlZ7yiCEHAMyE/s659/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-07-09%20122432.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;479&quot; data-original-width=&quot;659&quot; height=&quot;466&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvmy8pEjhOWL78XzHX_fhw-VK3l4qsFxlq8hI-ECbiwuPQznL6o8oAxlq9EBRIjdRLkauv6HauJesobBlNAS8xzFyH6V78F3KthrL3z1f2YvqgwgBfCFXVWmMXt1ER1J8fySc0nj3Mk_0FOP9QLySmQrlYxf0oWll0b6fFlCSl86lgSEQlZ7yiCEHAMyE/w640-h466/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-07-09%20122432.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;如上圖, 出現温度值, 那就是TMP102感測器已經可以正常運作了。&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;div&gt;下一步, 把藍牙功能跑起來, 可以先參考:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;https://learn.adafruit.com/circuitpython-nrf52840/overview&quot; target=&quot;_blank&quot;&gt;https://learn.adafruit.com/circuitpython-nrf52840/overview&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;基本上, Adafruit已經把許多工作做完, 包括MCU的驅動程式, 和手機上的App。nRF52840 MCU BLE驅動, 目前我們只要先搬2個目錄就好:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-WaKnrlRPEf8OkceDzZHHYznnXtm7MBAq3FrhMXwOqUyo6W_qm_ELHOdbJzrgnN-R4Hn9dzghjtnNPIMSxhGSYx6OAcCv5arP_ZNVZPhiUAkE-tZFXKZocxbid9UY3IEDweZG4-gs_yf1WRmgXJhpPwzFC-GPhnz39oC2vUyxY6VpJRNlmmanRG9Q8vA/s897/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-07-09%20125250.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;555&quot; data-original-width=&quot;897&quot; height=&quot;396&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-WaKnrlRPEf8OkceDzZHHYznnXtm7MBAq3FrhMXwOqUyo6W_qm_ELHOdbJzrgnN-R4Hn9dzghjtnNPIMSxhGSYx6OAcCv5arP_ZNVZPhiUAkE-tZFXKZocxbid9UY3IEDweZG4-gs_yf1WRmgXJhpPwzFC-GPhnz39oC2vUyxY6VpJRNlmmanRG9Q8vA/w640-h396/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-07-09%20125250.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;這2個目錄來自CircuitPython Librarys (adafruit cricuitpython bundle)&amp;nbsp;&lt;a href=&quot;https://circuitpython.org/libraries&quot; target=&quot;_blank&quot;&gt;https://circuitpython.org/libraries&lt;/a&gt;, 請依自己開發板上CircuitPython firmware版本來選擇相對應的下載版本。&lt;/div&gt;&lt;div&gt;手機上的App, 則到App Store, 找Bluefruit Connect。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;並將下面程式, 放到開發板上的code.py&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;py&quot;&gt;# CircuitPython Bluefruit LE Connect Plotter Example

import time
import board
import busio
from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService

from tmp102 import Tmp102
i2c = busio.I2C(board.P0_29, board.P0_31)
sensor = Tmp102(i2c, 0x48)
i2c.try_lock()
sensor.sleep()

ble = BLERadio()
uart_server = UARTService()
advertisement = ProvideServicesAdvertisement(uart_server)


while True:
    # Advertise when not connected.
    ble.start_advertising(advertisement)
    while not ble.connected:
        pass
    ble.stop_advertising()

    while ble.connected:
        sensor.set_one_shot()
        tempc = sensor.get_TempC(sensor.get_one_shot()) 
        print(tempc)
        uart_server.write(&quot;{}\n&quot;.format(tempc))
        time.sleep(1.0)
&lt;/code&gt;&lt;/pre&gt;
打開手機的Bluefruit Connect App, 連入後, 會看到如下圖:&lt;div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmbbJFTWfMyyFtGOwJgobd4JCI4zViYwX3kxmqFW1zl5WwRTJvSW5yfQ9QKc20MuB3iC65r-ZFnyCgwtuzqaz5iVXylT-nS7peWB7j2b-03qgrPnNPaHVD9-E4nbEk3mNvE0Rg4QKYflsn3L-G06fVnJ9BJVDj2xC4sxV6_Ejd1F8ZlxFvqg7lbq92Gk0/s2208/IMG_2493.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;2208&quot; data-original-width=&quot;1242&quot; height=&quot;640&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmbbJFTWfMyyFtGOwJgobd4JCI4zViYwX3kxmqFW1zl5WwRTJvSW5yfQ9QKc20MuB3iC65r-ZFnyCgwtuzqaz5iVXylT-nS7peWB7j2b-03qgrPnNPaHVD9-E4nbEk3mNvE0Rg4QKYflsn3L-G06fVnJ9BJVDj2xC4sxV6_Ejd1F8ZlxFvqg7lbq92Gk0/w360-h640/IMG_2493.jpg&quot; width=&quot;360&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;此時, 我們可以有2個地方查看温度值, 一個是UART的輸出, 一個是Plotter:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;點UART:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhT3boVQ5HwAU8d7rItbGFRWGI2RMXaujTcFiZ5XPNqycZQj9XdSuFob6-HeShk1CZ8oL3uiakrUEjytZPnHmXbDrj9SQ_MSDWN2ukm3tiJc19vw6pxtlS4jskTrpLeqH-ZZuEbnwWUkWNXUqk_ZYwRF4YtvSs4yES6nDyUrngAtVhX_FxTtZkGn3Czk-Y/s2208/IMG_2494.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;2208&quot; data-original-width=&quot;1242&quot; height=&quot;640&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhT3boVQ5HwAU8d7rItbGFRWGI2RMXaujTcFiZ5XPNqycZQj9XdSuFob6-HeShk1CZ8oL3uiakrUEjytZPnHmXbDrj9SQ_MSDWN2ukm3tiJc19vw6pxtlS4jskTrpLeqH-ZZuEbnwWUkWNXUqk_ZYwRF4YtvSs4yES6nDyUrngAtVhX_FxTtZkGn3Czk-Y/w360-h640/IMG_2494.PNG&quot; width=&quot;360&quot; /&gt;&lt;/a&gt;&lt;/div&gt;可以看到每秒都會收到一個温度值, 就和我們在終端機上看到的輸出是一樣的! 這當然是因為我們程式是這樣寫的。到這裡, 我們已經完成由BLE來收取nRF52840 Dongle取得的TMP102温度值。&lt;div&gt;&lt;br /&gt;&lt;div&gt;點Plotter:&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgE-EaRlqsyedqP4djwF3Nx18XaDU0ZaLa5seEvMuCRY5kaDCYa4z7MGpdUCXk5CFLfh4zBJiqcaKQuApUqwEQfR2CdJ0pM18DeJ0vGseKFLTCMuIQTRBBoxIUDzOElgzljJHrG-EK4KmRvXfgmie4Rujg5908IT_S1_Y5eVpKAp-IdesLs7Xb-2VKZEwE/s2208/IMG_2495.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;2208&quot; data-original-width=&quot;1242&quot; height=&quot;640&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgE-EaRlqsyedqP4djwF3Nx18XaDU0ZaLa5seEvMuCRY5kaDCYa4z7MGpdUCXk5CFLfh4zBJiqcaKQuApUqwEQfR2CdJ0pM18DeJ0vGseKFLTCMuIQTRBBoxIUDzOElgzljJHrG-EK4KmRvXfgmie4Rujg5908IT_S1_Y5eVpKAp-IdesLs7Xb-2VKZEwE/w360-h640/IMG_2495.PNG&quot; width=&quot;360&quot; /&gt;&lt;/a&gt;&lt;/div&gt;更好的是, Bluefruit Connect也提供畫圖的功能, 如上圖, 我們什麼都不用做, 只要選這個選項, 就可以看到温度的變化圖形。這樣是不是超簡單就做出BLE温度計來了呢?&amp;nbsp;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/419221146276313348/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/419221146276313348?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/419221146276313348'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/419221146276313348'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2023/07/part-2nrf52840-dongle-tmp102.html' title='超簡單做出低功耗藍牙温度計-Part 2(nRF52840 Dongle + TMP102 + CircuitPython)'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjQLjui6VgTlSYo1EI1dxWkmF8tAs_6m3pH_dkela9vH-miNhupTL4BQ_Ofxj2Dh-5akEzjV_hn8Xoa40IvazyJwV0LU5RapBvDWssuhBuvmywi3TzhQq6z_Av072SXIUHQihCzuUhGF8bZxcGQnhUkLGh6ZKwDeCC6a9KAtjamVKbX-wV7XcIQ5nO4j0/s72-c/2902521-40.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-5714819553223394181</id><published>2023-06-28T11:15:00.003+08:00</published><updated>2023-06-28T11:53:07.179+08:00</updated><title type='text'>超簡單做出低功耗藍牙温度計(nRF52840 Dongle + TMP102 + MircoPython)</title><content type='html'>&lt;p&gt;&amp;nbsp;MicroPython支援nRF52840 Dongle (pca10059), 這支在Mouser上只要台幣343左右就可以買到。買來後要燒錄MicroPython的firmware, 寫作時, MicroPython出到1.20.0版。燒錄方法, 可以參考&lt;a href=&quot;https://ops9.blogspot.com/2020/04/micropython-112nrf52840-dongle.html&quot; target=&quot;_blank&quot;&gt;燒錄Micropython 1.12至nRF52840 Dongle&lt;/a&gt;。這連結有更新, 文章下方有增加1.20.0版的燒錄方式, 不用擔心, 現在的燒錄方法是可以還原的, 以後仍可燒回其他firmware。&lt;/p&gt;&lt;p&gt;有了可跑MicroPython的nRF52840 Dongle後, 可以直接寫Python程式來實作低功耗藍牙温度計。其實不用傷腦筋如何寫, MicroPython官網就有一個範例程式, 直接拿來用就可以有這個功能了! 這麼好, 當然了, 這不就是MicroPython給我們的承諾嗎? 簡單好用! 連結在此:&amp;nbsp;&lt;a href=&quot;https://github.com/micropython/micropython/blob/master/ports/nrf/examples/ubluepy_temp.py&quot; target=&quot;_blank&quot;&gt;ubluepy_temp.py&lt;/a&gt;&lt;/p&gt;&lt;p&gt;註: 這個程式和MicroPython 1.20.0在nRF52840上, 會有RTC被用掉的問題, 要改一下! 如下圖, 1改成2就可以了。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAiKAx3u-eNmJi33Lutx0RTOzOGe_H9V8K_CTTvVb6hTpydoYoSZfmGq9bm3_F_RysnBWDV2D-71rqAkTU22_U3XeQCSbLwxKgTQm_T1pK_rDOqpO5Ke2ZXqsy7Htae9dm0DEHL-sykMfG5HFWX5o5QRCZnJebje4-zhvNTIyr_o-lQJJ4kceNmpPuFeE/s660/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20102029.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;264&quot; data-original-width=&quot;660&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAiKAx3u-eNmJi33Lutx0RTOzOGe_H9V8K_CTTvVb6hTpydoYoSZfmGq9bm3_F_RysnBWDV2D-71rqAkTU22_U3XeQCSbLwxKgTQm_T1pK_rDOqpO5Ke2ZXqsy7Htae9dm0DEHL-sykMfG5HFWX5o5QRCZnJebje4-zhvNTIyr_o-lQJJ4kceNmpPuFeE/s16000/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20102029.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;改好, 直接跑, 然後用手機上的nRF Connect App (或其他BLE App), 找micr_temp這個裝置, 連接上去, 注意連接上去後, Dongle的LED燈會亮起來。找Environmental Sensing服務下的Temperature特徵值, 按下通知啟用, 並修改Data parser為符號整數。查看log部份, 就可以看到每5秒左右會更新一次温度值。如下圖:&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0BeFxB4cQDF3tSmvIFiFMSOA0I1XUn1gPNlHMUCSo5Qev0i5YIHqE7AGiO-oLhW4MsUKHt4TuVDB2RO33Rvz03gvQuFE9hNI-3qtZQ0zivfGB02_l5iuydZmy6eFPp_q48dkj-IVO_Z6ikKbAlJMw67fYehIq673fs_v8GT9ZGkPpP4b8g2k6l8yRTB4/s831/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20101622.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;831&quot; data-original-width=&quot;498&quot; height=&quot;640&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0BeFxB4cQDF3tSmvIFiFMSOA0I1XUn1gPNlHMUCSo5Qev0i5YIHqE7AGiO-oLhW4MsUKHt4TuVDB2RO33Rvz03gvQuFE9hNI-3qtZQ0zivfGB02_l5iuydZmy6eFPp_q48dkj-IVO_Z6ikKbAlJMw67fYehIq673fs_v8GT9ZGkPpP4b8g2k6l8yRTB4/w384-h640/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20101622.png&quot; width=&quot;384&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;如上圖, 第2點所圈起處, 看到2800, 這表示為28度C。如果沒有修改Data parser, 預設會是看到16進位數值, 如上圖第3點所圈起處0xF00A, 這個格式我們人類看不懂!&lt;/p&gt;&lt;p&gt;大家都注意到了吧! 現在温度都出現2700, 2800, 2900之類的, 後面那2個0都不會出現其他數字, 這是因為現在這個範例程式是存取nRF52840內建的温度感測器, 而這個温度感測器基本是查看MCU的温度用的, 而且目前firmware的實作也沒有取得小數點部份, 可能覺得沒必要! 而且, MCU通常會發熱, 比實際上的環境温度要高一些。&lt;/p&gt;&lt;p&gt;因此, 以下使用TMP102這顆TI的温度感測器來取得較為接近實際環境的温度。修改部份也很簡單, 只要加入TMP102的驅動, 再改一下上面這個範例程式就好。&lt;/p&gt;&lt;p&gt;但首先要處理一下硬體接線:&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO6tdtwAjA1WmVXMqFrFVc-FDVTF6RhxbjSXKczgDMdl-qUCmetnGZWD2m5xA07Z5blh03uWVJ6CCrOIUJOts8jIg8ouH3gvDvVjMuj_XFGShpj4BpX1_DcmOt02qJrBD_yyWk-bVBQWx0v4j8XQPwea7lxV4nUxZ6vXt5COGfA-UFnCeAr5F1SMKpXmA/s592/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20105534.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;592&quot; data-original-width=&quot;418&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO6tdtwAjA1WmVXMqFrFVc-FDVTF6RhxbjSXKczgDMdl-qUCmetnGZWD2m5xA07Z5blh03uWVJ6CCrOIUJOts8jIg8ouH3gvDvVjMuj_XFGShpj4BpX1_DcmOt02qJrBD_yyWk-bVBQWx0v4j8XQPwea7lxV4nUxZ6vXt5COGfA-UFnCeAr5F1SMKpXmA/w226-h320/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20105534.png&quot; width=&quot;226&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIM5ZDBoYKWNAl6pOqGepf8vvon6qRdeoUwRBjEEHg8XVFcJvUfs_bRa9VnQiN0CR9IKHrQjljZyOMtRgFLXXvmpP2JGz9b4KyujNZKXMHZ08cxK7kTkgsh0_lmMJK63QcYU3vAiIRlq2lTad09VP8VO4MRZGuFXPjPfVsqaZPDju1Am1XpKKT3IOGos0/s500/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20105559.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;500&quot; data-original-width=&quot;384&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIM5ZDBoYKWNAl6pOqGepf8vvon6qRdeoUwRBjEEHg8XVFcJvUfs_bRa9VnQiN0CR9IKHrQjljZyOMtRgFLXXvmpP2JGz9b4KyujNZKXMHZ08cxK7kTkgsh0_lmMJK63QcYU3vAiIRlq2lTad09VP8VO4MRZGuFXPjPfVsqaZPDju1Am1XpKKT3IOGos0/s320/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20105559.png&quot; width=&quot;246&quot; /&gt;&lt;/a&gt;&lt;/div&gt;其實也很簡單, I2C的連線, 只要連接4條線就可以, VCC, GND, SDA, SCL。&lt;div&gt;TMP102&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;nRF52840 Dongle&lt;/div&gt;&lt;div&gt;VCC&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; VDD OUT&lt;/div&gt;&lt;div&gt;GND&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;GND&lt;/div&gt;&lt;div&gt;SDA&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 0.29&lt;/div&gt;&lt;div&gt;SCL&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 0.31&lt;br /&gt;&lt;p&gt;TMP102的驅動, 請參考&lt;a href=&quot;https://ops9.blogspot.com/2023/05/ti-tmp102.html&quot; target=&quot;_blank&quot;&gt;再論TI TMP102&lt;/a&gt;這篇文章的最下方, 驅動的程式名字取為tmp102.py。請先將之存入Dongle。接著對原本的範例程式ubluepy_temp.py做以下修改即可:&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdZDq0yyJEtBR1Z0MHOBvcfIyYdjkLqBRLQ5u3CVGlsXsErgKr-I05VoclSb0u5jzNX_ooB1zLjbhiU99MfX5nx19GzlwIIGtMLbiR0oIsl1GBQ0y_-qX3WyeUahD2WmMyzsGBoLh36gP2kzqqJNToD3FYeWK5uNpESZ7d0eqH29SuWjcSu3_iFsRRMCA/s698/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20110719.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;328&quot; data-original-width=&quot;698&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdZDq0yyJEtBR1Z0MHOBvcfIyYdjkLqBRLQ5u3CVGlsXsErgKr-I05VoclSb0u5jzNX_ooB1zLjbhiU99MfX5nx19GzlwIIGtMLbiR0oIsl1GBQ0y_-qX3WyeUahD2WmMyzsGBoLh36gP2kzqqJNToD3FYeWK5uNpESZ7d0eqH29SuWjcSu3_iFsRRMCA/s16000/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20110719.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinZ1UQswQhzKaN5VvgsAj-hhK0bLW3B75cHbrMuKGwzzhDoIMVNaTVTlEsANRfzTHFaoXyW5_jwpniJv3RkvMpjbZb1LqEJTQO6r_IDFouHEGIdZt-2ugbBJEzWj-FHBM6vvwX_SsDGr82pZX_leMO0K3lWDxmHNCHnxYBxO08hNr973muEX-sxhyu9fM/s667/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20110845.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;389&quot; data-original-width=&quot;667&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinZ1UQswQhzKaN5VvgsAj-hhK0bLW3B75cHbrMuKGwzzhDoIMVNaTVTlEsANRfzTHFaoXyW5_jwpniJv3RkvMpjbZb1LqEJTQO6r_IDFouHEGIdZt-2ugbBJEzWj-FHBM6vvwX_SsDGr82pZX_leMO0K3lWDxmHNCHnxYBxO08hNr973muEX-sxhyu9fM/s16000/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20110845.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;這樣就好了, 改好存檔後, soft reset, 再跑, 然後用手機的nRF Connect App連入, 查看:&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrDBHZkbSkVqA8MSaPoKsaNoaJpRKTlDkOJpDwpt3_p_OIIvXIOs4ltElEPM_Ab_a53mxKWYs8OHNkaanjJCgBcaIWcK0RWHyJSWL_qoJ_ErE6VeWLLv11ysLuddPv42n75nd1rYVd8jtiXpD0dLnJhw7P5aRntjXabjj13Dv-CqwDQOTB4YdLXlF416Y/s833/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20111154.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;833&quot; data-original-width=&quot;495&quot; height=&quot;640&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrDBHZkbSkVqA8MSaPoKsaNoaJpRKTlDkOJpDwpt3_p_OIIvXIOs4ltElEPM_Ab_a53mxKWYs8OHNkaanjJCgBcaIWcK0RWHyJSWL_qoJ_ErE6VeWLLv11ysLuddPv42n75nd1rYVd8jtiXpD0dLnJhw7P5aRntjXabjj13Dv-CqwDQOTB4YdLXlF416Y/w380-h640/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20111154.png&quot; width=&quot;380&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;(記得改一下Data parser格式)就可以看到如上圖2475代表24.75度C的結果了, 這個温度值就比較接近實際環境的温度值了, 而且可以出現小數點以下, 較為精確的數值。&lt;/p&gt;&lt;p&gt;因為nRF52840 Dongle預設是用來接USB埠的, 所以我們可以拿一個手機充電器(有USB接頭的), 直接插進去, 這樣只要有電源插頭的地方就可以放我們的低功耗藍牙温度計了! 如下圖:&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixn4K27aO1SwpDJlDzb0UP1Sy45KDyn1WxU7uGYo_zrHhp8KoOfS4kOg4itBeCTSfRr6WpzhV1QOZkhnkuHP6Zdv2mQYXmOcTFO6wjCB6nSYYtjGA8IGxsteh-WLuODPlAciqym1yLRaRMq7gSX0w2mESEqKxS76ZJoaD2yU4XJRUmuyt2x5OSU3Nr2W8/s629/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20112628.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;629&quot; data-original-width=&quot;526&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixn4K27aO1SwpDJlDzb0UP1Sy45KDyn1WxU7uGYo_zrHhp8KoOfS4kOg4itBeCTSfRr6WpzhV1QOZkhnkuHP6Zdv2mQYXmOcTFO6wjCB6nSYYtjGA8IGxsteh-WLuODPlAciqym1yLRaRMq7gSX0w2mESEqKxS76ZJoaD2yU4XJRUmuyt2x5OSU3Nr2W8/s320/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20112628.png&quot; width=&quot;268&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;再修改一下boot.py, 加入一開機就跑我們改好的範例程式就大功告成。&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/5714819553223394181/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/5714819553223394181?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/5714819553223394181'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/5714819553223394181'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2023/06/nrf52840-dongle-tmp102-mircopython.html' title='超簡單做出低功耗藍牙温度計(nRF52840 Dongle + TMP102 + MircoPython)'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAiKAx3u-eNmJi33Lutx0RTOzOGe_H9V8K_CTTvVb6hTpydoYoSZfmGq9bm3_F_RysnBWDV2D-71rqAkTU22_U3XeQCSbLwxKgTQm_T1pK_rDOqpO5Ke2ZXqsy7Htae9dm0DEHL-sykMfG5HFWX5o5QRCZnJebje4-zhvNTIyr_o-lQJJ4kceNmpPuFeE/s72-c/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-06-28%20102029.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4479604189222772504.post-5585058235671587740</id><published>2023-05-30T10:55:00.002+08:00</published><updated>2023-06-05T15:57:33.842+08:00</updated><title type='text'>再論TI TMP102</title><content type='html'>&lt;p&gt;&amp;nbsp;雖然TMP102只是一個温度感測器, 但因為它使用I2C溝通界面, 讓我們可以學習I2C的用法, 而且架構簡單, 用起來不難, 但又有許多功能可以設定, 玩起來很有意思, 最主要的是其温度感測算是很準, 所以我一直很喜歡這顆。加上網路上也有很多人在用, 討論的文章和驅動程式都很容易找到, 所以這裡我想再談一下這顆的一些用法。&lt;/p&gt;&lt;p&gt;1. 驅動程式的寫法:&amp;nbsp;&lt;/p&gt;&lt;p&gt;其實可以不用自己寫驅動程式, 如果你使用Arduino, 那Sparkfun已經幫大家寫好了:&amp;nbsp;&lt;a href=&quot;https://github.com/sparkfun/SparkFun_TMP102_Arduino_Library&quot; target=&quot;_blank&quot;&gt;SparkFun_TMP102_Arduino_Library&lt;/a&gt;&amp;nbsp;請直接拿去用就好了! 如果你使用MicroPython, 那khoulihan也寫好一個:&lt;span face=&quot;Arial, Tahoma, Helvetica, FreeSans, sans-serif&quot; style=&quot;color: #222222;&quot;&gt;&lt;span style=&quot;background-color: white; font-size: 13.2px;&quot;&gt;&amp;nbsp;&lt;a href=&quot;https://github.com/khoulihan/micropython-tmp102&quot; target=&quot;_blank&quot;&gt;khoulihan/micropython-tmp102&lt;/a&gt;,&amp;nbsp;&lt;/span&gt;&lt;/span&gt;他其實已經寫得很好。&lt;/p&gt;&lt;p&gt;但是我還是自己用MicroPython再寫了一次, 原因是khoulihan的驅動太完整了, TMP102所有的功能都實作了! 可惜的是我想用的一個開發板的Flash空間太小, 放了這個驅動後, 剩下的空間就太小了, 要寫其他的程式就很受限! 另外, 在自己改寫的過程中, 我發現自己又學到一些東西。雖然多花了幾天時間在嘗試, 還是收穫不少!&lt;/p&gt;&lt;p&gt;其實2017年在玩PyMata的時候, 就已經寫過TMP102的驅動, 參見&lt;a href=&quot;https://app.box.com/file/255130406555&quot; target=&quot;_blank&quot;&gt;python code for pymata tmp102&lt;/a&gt;, 但這個是架在PyMata之上的, 基本上是在PC上面執行, 稱之為驅動, 似乎有些奇怪。但程式邏輯和想法基本上相同。&lt;/p&gt;&lt;p&gt;操作TMP102的方法, 很簡單, 就是設定其暫存器的值就可以了, 如下圖 (取自TMP102的datasheet), TMP102主要有4個暫存器, (還有一個指位暫存器Pointer Register), 要取得温度值, 就讀取Temperature Register的內容值, 再做一些格式轉換即可。要讓TMP102進入省電的Shutdown模式, 就只要將Configuration Register內的某一個位元設成1就可以了。問題是如何指定要存取那個暫存器呢? 那就要在指位暫存器先指定就可以了, 例如, 將指位暫存器設成0x01, 就可以存取Configuration Register。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYqKwvks-EDcIEdVQ1vniGmo4Q3-LkajxVUW7pxUvjqP17U6L6fy1t_otfdIj8179NBcqapVVzQCzmsjckJ58V_Nng2k9ZHOIr7Qfr9jZlwavWVMJ0fYhZaTohTarEWQvG-cQRmR7ig4FpMq4wOZDazNelkCOpsA854jwuOpScwtE0iarEQwR1FCDH/s669/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-29%20175605.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;476&quot; data-original-width=&quot;669&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYqKwvks-EDcIEdVQ1vniGmo4Q3-LkajxVUW7pxUvjqP17U6L6fy1t_otfdIj8179NBcqapVVzQCzmsjckJ58V_Nng2k9ZHOIr7Qfr9jZlwavWVMJ0fYhZaTohTarEWQvG-cQRmR7ig4FpMq4wOZDazNelkCOpsA854jwuOpScwtE0iarEQwR1FCDH/s16000/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-29%20175605.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;不過, 在讀或寫暫存器值時, 指位暫存器值的設定方式有點不太相同! 以下分別說明:&lt;/p&gt;&lt;p&gt;讀取暫存器內容值時, 先下一個I2C寫入的指令, 寫入SLA及指位暫存器的值; 然後再下I2C讀取的的指令, 這樣就可以讀到指位暫存器所指之暫存器之內容值了。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6P6E8gnYQ3nivFyPdBu28TvzyQXfAa4g7Ia16J9AN5ZvVDJkbj0MyHUggjlH84Q6bvWbxW-vXrupOj13U3xKcg-DQatFyE_S4bd6xPCHbZauJtUJbLnAE8ZOcry5_GqTxrgnyBsazXljutuy1Ingb42yos9y32_J5npMi1WrmJct1wGX0qdcv_iOk/s579/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-29%20180948.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;451&quot; data-original-width=&quot;579&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6P6E8gnYQ3nivFyPdBu28TvzyQXfAa4g7Ia16J9AN5ZvVDJkbj0MyHUggjlH84Q6bvWbxW-vXrupOj13U3xKcg-DQatFyE_S4bd6xPCHbZauJtUJbLnAE8ZOcry5_GqTxrgnyBsazXljutuy1Ingb42yos9y32_J5npMi1WrmJct1wGX0qdcv_iOk/s16000/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-29%20180948.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;上圖(取自TMP102 datasheet), 就是讀取暫存器內容值時使用的I2C指令, 這其實是下2個指令, 一寫一讀。以邏輯分析儀來看, 如下圖, 可能清楚一些。第一個I2C指令寫入0x01的值給指位暫存器, 告訴它接下來要讀取那個暫存器(0x01表示Configuration Register), 第二個I2C指令去讀取時, 就會讀到剛才指定的暫存器的值了。即W[0x48] 0x01, 表示告訢slave address為0x48的TMP102, 後面的讀取是要讀0x01暫存器的值。因此, 後面的R[0x48] 0xE1 0xA0, 讀到的0xE1 0xA0就是暫存器0x01的內容值。&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaRjl58P8pHUWBTgQdcnvwMhPLUMI1xXyuRqupeD4th_ZeFmcpvQ0ff6JKjnY_n27xe-B4lfDkfy0VwU0a6KhzvxWZHz-B4PMmFN1t1szbMjZrGfdOxClbdanBSZedmz1WfUEUVKbOfCOx06aewX_uCj5cA2iifinZGXuvZHexX1i6zFW3JJahw6GC/s913/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-29%20181732.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;181&quot; data-original-width=&quot;913&quot; height=&quot;127&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaRjl58P8pHUWBTgQdcnvwMhPLUMI1xXyuRqupeD4th_ZeFmcpvQ0ff6JKjnY_n27xe-B4lfDkfy0VwU0a6KhzvxWZHz-B4PMmFN1t1szbMjZrGfdOxClbdanBSZedmz1WfUEUVKbOfCOx06aewX_uCj5cA2iifinZGXuvZHexX1i6zFW3JJahw6GC/w640-h127/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-29%20181732.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;寫入暫存器時, 如下圖(取自TMP102 datasheet), 則是一個I2C寫入指令而已, 但要先寫入的是要寫入那個暫存器(即要填入指位暫存器的數值), 接著是第一個位元組, 然後是第二個位元組。因為TMP102的4個主要暫存器都是二個位元組的大小, 所以寫入指令在指位暫存器後都是帶二個位元組。&lt;/p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYEg1tQckoMm1WSUNo8JL2LrT3LvqE8vJOpaFlBKicuVS4QpV6jH-fn4ls6eOzGpQ7QiULdGzri0IunTFwi8v22lq8iD3LJ_RKfcXTsI8hdjPzlgmD0i1B7Y82bww8r4pQYzE0FuFlwjtkCeL0iuqSjx9VABLkG7_QSWAukTEJBuumLcWzexJFajAV/s593/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-30%20081658.png&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;293&quot; data-original-width=&quot;593&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYEg1tQckoMm1WSUNo8JL2LrT3LvqE8vJOpaFlBKicuVS4QpV6jH-fn4ls6eOzGpQ7QiULdGzri0IunTFwi8v22lq8iD3LJ_RKfcXTsI8hdjPzlgmD0i1B7Y82bww8r4pQYzE0FuFlwjtkCeL0iuqSjx9VABLkG7_QSWAukTEJBuumLcWzexJFajAV/s16000/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-30%20081658.png&quot; /&gt;&lt;/a&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;同樣用邏輯分析儀來看一下, 可能清楚一點。如下圖, W[0x48] 0x01 0xE1 0xA0, 表示向slave address為0x48的TMP102下寫入指令, 將數值寫到0x01暫存器, 第一個位元組寫入0xE1, 第二個位元組寫入0xA0。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj99RFSEGKsOhn--9FmRg3LuT1o8Z_LjgJY726AEW0gIAdnO4g8kJ2yhvDp5-oTlyD40fjCqaZZAp37K3Jpx05_K7Bj0jNLWyNgGTA355tm7UOkRa1wW2OqCeyNHxjB2gVDpvgBfdjmWamqHXUT8OMUEFn6DqK520tubFzycNmKOShIICo0WH2mh2G8/s858/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-30%20082709.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;186&quot; data-original-width=&quot;858&quot; height=&quot;139&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj99RFSEGKsOhn--9FmRg3LuT1o8Z_LjgJY726AEW0gIAdnO4g8kJ2yhvDp5-oTlyD40fjCqaZZAp37K3Jpx05_K7Bj0jNLWyNgGTA355tm7UOkRa1wW2OqCeyNHxjB2gVDpvgBfdjmWamqHXUT8OMUEFn6DqK520tubFzycNmKOShIICo0WH2mh2G8/w640-h139/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-30%20082709.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;了解了如何用I2C和TMP102溝通以(讀取)寫入值到其暫存器之後, 要操作TMP102就很簡單了, 因為所有的功能都是操作其暫存器的值來進行的。例如, 可以讓TMP102進入Shutdown模式, 這個時候, 其耗電量就可以降到0.5uA左右, 非常省電。&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The Shutdown-mode bit saves maximum power by shutting down all device circuitry other than the serial interface, reducing current consumption to typically less than 0.5 μA. Shutdown mode enables when the SD bit is 1; the device shuts down when current conversion is completed. When SD is equal to 0, the device maintains a continuous conversion state.&lt;/p&gt;&lt;/blockquote&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSOIH4-RuhKHvC8_8w5m_8LtzSIu0q8ujpFRQMe3Quf_Kd1alNLe4bPABeBboe_59nr77O7ZzmvbwA5tHYfSn0KvhAgDJeswOf_TzEKFtDWPdwo5K87RMg_koXJrguCGVFCzO--uMiHh9FUqRoESXtR9zPPJcT8Tre_Yv72IXO49TnZ8VBdYMfUKfy/s666/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-30%20083831.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;155&quot; data-original-width=&quot;666&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSOIH4-RuhKHvC8_8w5m_8LtzSIu0q8ujpFRQMe3Quf_Kd1alNLe4bPABeBboe_59nr77O7ZzmvbwA5tHYfSn0KvhAgDJeswOf_TzEKFtDWPdwo5K87RMg_koXJrguCGVFCzO--uMiHh9FUqRoESXtR9zPPJcT8Tre_Yv72IXO49TnZ8VBdYMfUKfy/s16000/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-30%20083831.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;由上表(取自TMP102 datasheet)可以找到SD這個位元是在0x01 Configuration Register這個暫存器的第一個位元組(Byte 1)的D0這個位置。由Datasheet的文字說明, 我們知道將SD設為1, TMP102就會進入Shutdown模式, 較為省電許多。那這個功能的驅動要如何寫就很明顯了, 因為我們無法只去改變一個位元(bit), 我們最小的寫入單位是位元組(byte), 所以必須將原本暫存器的內容讀出, 然後用位元運算去改變一個位元, 再將整個位元組寫回去。&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;用MicroPython來寫, 如下程式, 第一行程式將Configuration Register這個暫存器的內容取出放到config位元組陣列, 第二行程式將config[0](即暫存器的第一個位元組)的D0位元(使用MASK SHUTDOWN_BIT=0x01)設成1(_set_bit), 第三行程式再將改過之後的內容寫回去原來的暫存器。這樣就達到我們使TMP102進入省電模式的目的了。&lt;/div&gt;
&lt;pre&gt;  &lt;code class=&quot;py&quot;&gt;
    def sleep(self):
        config = bytearray(self._get_config())
        config[0] = _set_bit(config[0], SHUTDOWN_BIT)
        self._set_config(config)
  &lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
當然, 由Shutdown模式回到正常的連續轉換模式, 也就是把SD改回0(_clear_bit), 如此而已。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
&lt;pre&gt;&lt;code class=&quot;py&quot;&gt;
    def wakeup(self):
        config = bytearray(self._get_config())
        config[0] = _clear_bit(config[0], SHUTDOWN_BIT)
        self._set_config(config) 
  &lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;這裡讀取暫存器值和寫入暫存器值的函式, 見下列程式碼, 基本上是由khoulihan的程式修改一點點來的。其程式碼做的事情, 就是前面說明的用I2C寫入和讀取指令來做TMP102暫存器讀寫的動作而已。這裡可以學到一些小技巧, 即使MicroPython似乎是一個語言, 但其I2C部份的指令, 看來因不同開發板硬體不同, 而有2種不同語法習慣! (readfrom vs. recv; writeto vs. send) khoulihan使用了try except 語法來解決這個困擾, 這樣就可以跨不同硬體開發板。而讀取暫存器的動作, I2C送回來的2個bytes, 其資料型態為Bytes, khoulihan使用bytearray()這用法將其由Bytes轉成Byte Array型態, 以方便直接存取其中一個位元組。&lt;/div&gt;

&lt;pre&gt; &lt;code class=&quot;py&quot;&gt;
    def _read_register(self, register):
        self._write_register(register)
        try:
            val = self.bus.readfrom(self.address, 2)
        except AttributeError:
            val = self.bus.recv(2, addr=self.address)
        return val
    
    def _write_register(self, register, value=None):
        bvals = bytearray()
        bvals.append(register)
        if value is not None:
            for val in value:
                bvals.append(val)
        try:
            self.bus.writeto(self.address, bvals)
        except AttributeError:
            self.bus.send(bvals, addr=self.address)
            
    def _get_config(self):
        return self._read_register(REGISTER_CONFIG)
    
    def _set_config(self, config):
        self._write_register(REGISTER_CONFIG, config)
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;我使用三用電表來量一下耗電量, 下圖是TMP102進入Shutdown模式時的耗電流, 真的如Datasheet所說的, 不到0.5uA。這時我使用的是Nordic nRF52840DK這個開發板。&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDOv2yJKQqR-I5SF7THRtTcq0Q_80jEo1smNexyaZtw_75B6Ne0bgqHC-Nn2phzbq0XGy6Lh5pBSINOxCP9l1MQqD5zskfDO06fp2IoJdvyKCPy_6OEreDPiqSQo2pW1c-WJ83rENnKqJorjZq1JPBYiylHWjxroD0u1AU2PVWkoKJHdeS6zgRgkm-/s813/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-30%20100234.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;611&quot; data-original-width=&quot;813&quot; height=&quot;481&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDOv2yJKQqR-I5SF7THRtTcq0Q_80jEo1smNexyaZtw_75B6Ne0bgqHC-Nn2phzbq0XGy6Lh5pBSINOxCP9l1MQqD5zskfDO06fp2IoJdvyKCPy_6OEreDPiqSQo2pW1c-WJ83rENnKqJorjZq1JPBYiylHWjxroD0u1AU2PVWkoKJHdeS6zgRgkm-/w640-h481/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-30%20100234.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;當我把TMP102回復成一般模式(即連續轉換模式)時, 耗電量開始跳動, 因為預設是每秒進行4次轉換(即將取得類比温度轉換成數位值並存入0x00温度暫存器), 每次轉換時都會比較耗電。三用電表是顯示平均值, 所以只能看到在跳動的數字, 耗電量可能在60-12uA之間, 如下圖。&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOkY4so16P8dTU8KnVBz9HDEFeXO4Yb5XtY5oTDiVEvb2NNo2FSQ_8wNsTjYaAskkWC8mmjjram7z9v9th8B_i202CJmFF7LySUYaJjAu09zj-RSqjhL0u6G8ijfoTpTbhSEbM8F8RoPcNbecq5_9x-K9enctVvBqZ-QsY3sKRqxv06joeHpqwkw7T/s846/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-30%20101443.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;601&quot; data-original-width=&quot;846&quot; height=&quot;454&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOkY4so16P8dTU8KnVBz9HDEFeXO4Yb5XtY5oTDiVEvb2NNo2FSQ_8wNsTjYaAskkWC8mmjjram7z9v9th8B_i202CJmFF7LySUYaJjAu09zj-RSqjhL0u6G8ijfoTpTbhSEbM8F8RoPcNbecq5_9x-K9enctVvBqZ-QsY3sKRqxv06joeHpqwkw7T/w640-h454/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-30%20101443.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;所以確實, 這樣可以用來控制TMP102的行為。有用的是這個驅動是可以跨硬體的, 如下圖Thonny這個工具, (1)只要把我自己改的驅動tmp102.py複製到開發板上的flash, (2)寫一個簡單的MicroPython程式, 如此圖中的tmp102_temp.py, 修改一下因不同板子而不同的 I2C接腳編號, 就可以叫TMP102工作了。如上圖, 我還有一個Raspberry Pi Pico開發板, 我也把驅動copy過去, 然後改了一下tmp102_temp.py, 之後就可以在RP Pico上讀到TMP102測到的温度了。&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiycdLe2oUg7nEHHaVfX9FQFr6oGfP08aYJHuzMIV266zqX9NbQRsI_pYKRd2jUtmNsX9Gc08lMeg_MrXTcNLEFqbPUbFXgIASwafhwavgdjB8sJZnSRiXPhgM72GsVJjM1E9hk6G7AtIim_G011fX9qpUqLwbz77lSVFIMf9uMGrFf9zfmrq0G8V-_/s1008/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-30%20101923.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;801&quot; data-original-width=&quot;1008&quot; height=&quot;508&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiycdLe2oUg7nEHHaVfX9FQFr6oGfP08aYJHuzMIV266zqX9NbQRsI_pYKRd2jUtmNsX9Gc08lMeg_MrXTcNLEFqbPUbFXgIASwafhwavgdjB8sJZnSRiXPhgM72GsVJjM1E9hk6G7AtIim_G011fX9qpUqLwbz77lSVFIMf9uMGrFf9zfmrq0G8V-_/w640-h508/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-30%20101923.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;因為我只需要one-shot並保留原本連續轉換模式的功能, 這樣才能省電且驅動程式較小, 因此沒有全部TMP102的功能, 如果有同樣需求的朋友, 我仍將程式碼放在這裡。程式碼最後面註解部份為此驅動的用法, 如程式註解對應二個用法, 一個為預設用法, 一個為省電用法。&lt;/div&gt;&lt;pre&gt;&lt;code class=&quot;py&quot;&gt;REGISTER_TEMP = 0
REGISTER_CONFIG = 1

SHUTDOWN_BIT = 0x01
ONE_SHOT_BIT = 0x80

def _set_bit(b, mask):
    return b | mask

def _clear_bit(b, mask):
    return b &amp;amp; ~mask

class Tmp102(object):
    
    def __init__(self, bus, address):
        self.bus = bus
        self.address = address
        
    def get_TempC(self, data):
        lo = data[1]
        hi = data[0]
        temp = ((hi * 256) + lo) &amp;gt;&amp;gt; 4
        return temp * 0.0625
    
    def _read_register(self, register):
        self._write_register(register)
        try:
            val = self.bus.readfrom(self.address, 2)
        except AttributeError:
            val = self.bus.recv(2, addr=self.address)
        return val
    
    def _write_register(self, register, value=None):
        bvals = bytearray()
        bvals.append(register)
        if value is not None:
            for val in value:
                bvals.append(val)
        try:
            self.bus.writeto(self.address, bvals)
        except AttributeError:
            self.bus.send(bvals, addr=self.address)
            
    def _get_config(self):
        return self._read_register(REGISTER_CONFIG)
    
    def _set_config(self, config):
        self._write_register(REGISTER_CONFIG, config)
        
    def temperature(self):
        return bytearray(self._read_register(REGISTER_TEMP))
            
    def wakeup(self):
        config = bytearray(self._get_config())
        config[0] = _clear_bit(config[0], SHUTDOWN_BIT)
        self._set_config(config)    
    def sleep(self):
        config = bytearray(self._get_config())
        config[0] = _set_bit(config[0], SHUTDOWN_BIT)
        self._set_config(config)
    
    def set_one_shot(self):
        config = bytearray(self._get_config())
        config[0] = _set_bit(config[0], ONE_SHOT_BIT)
        self._set_config(config)
        
    def get_one_shot(self):
        while True:
            config = bytearray(self._get_config())
            data1 = (config[0] &amp;gt;&amp;gt; 7) &amp;amp; 0x01
            if data1 != 0:
                break
        return bytearray(self._read_register(REGISTER_TEMP))
    
&#39;&#39;&#39;
from xxx import Tmp102
from machine import I2C, Pin
i2c = I2C(0, scl=Pin(29), sda=Pin(31))
sensor = Tmp102(i2c, 0x48)

# periodic read
sensor.wakeup()
sensor.get_TempC(sensor.temperature())

# one-shot read
sensor.sleep()
sensor.set_one_shot()
sensor.get_TempC(sensor.get_one_shot())
&#39;&#39;&#39;
&lt;/code&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://ops9.blogspot.com/feeds/5585058235671587740/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4479604189222772504/5585058235671587740?isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/5585058235671587740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4479604189222772504/posts/default/5585058235671587740'/><link rel='alternate' type='text/html' href='http://ops9.blogspot.com/2023/05/ti-tmp102.html' title='再論TI TMP102'/><author><name>雨恩</name><uri>http://www.blogger.com/profile/16049053007338975866</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYqKwvks-EDcIEdVQ1vniGmo4Q3-LkajxVUW7pxUvjqP17U6L6fy1t_otfdIj8179NBcqapVVzQCzmsjckJ58V_Nng2k9ZHOIr7Qfr9jZlwavWVMJ0fYhZaTohTarEWQvG-cQRmR7ig4FpMq4wOZDazNelkCOpsA854jwuOpScwtE0iarEQwR1FCDH/s72-c/%E8%9E%A2%E5%B9%95%E6%93%B7%E5%8F%96%E7%95%AB%E9%9D%A2%202023-05-29%20175605.png" height="72" width="72"/><thr:total>0</thr:total></entry></feed>