博客 | Blog

局域网控制小米智能插座

宿舍的上网环境是歌华有线,走的方式是很多年前在计算机知识科普书籍上看到的有线电视同轴电缆方式。 不知道是线路问题还是运营商赠送的 modem 问题,经常掉线,而且掉线后需要重启 modem 才能恢复。 这个过程需要手动操作,很麻烦。因为出问题的时候 modem 后台大部分时候也无法访问,所以通过 web 重启的选择也不可行。

所以我想到了用智能插座来控制 modem 的电源。这样就可以通过后台程序来自动重启 modem 了。但是 这里有个悖论问题是,modem 出问题的时候整个网络是不联通的,也就没办法通过互联网控制智能插座。 能不能通过局域网访问和控制智能插座呢?在网上一番搜寻找到了小米智能插座相关的一系列博客文章, 证明了这个方案的可行性。我主要参考了这篇小米智能插座监控设备耗电,并自动断电 感谢作者的分享,也简单记录一下我的实现过程。

我买的具体型号为小米智能插座3,没太研究明白到底有多少类似的款,应该大部分都是能满足要求的。 主要步骤如下:

1. 配置设备 #

在配置好网络添加进入米家APP后,可以在米家APP或者路由器后台获得智能插座的 IP 地址。

2. 获取设备 Token #

采用 Xiaomi-cloud-tokens-extractor 提供的方法获取,运行后可以获取局域网所有设备的 token 和型号等信息。 示例输出:

NAME:     Mijia Smart Plug 3
ID:       <id>
MAC:      <mac>
IP:       192.168.1.1xx
TOKEN:    <token>
MODEL:    cuco.plug.v3
---------
NAME:     Mi Control Hub
ID:       <id>
MAC:      <mac>
IP:       192.168.1.1xx
TOKEN:    <token>
MODEL:    lumi.gateway.v3

3. 获取设备接口信息 #

通过小米/米家产品库网站 https://home.miot-spec.com/ 获取设备的接口信息。 搜索 cuco.plug.v3 找到对应页面 https://home.miot-spec.com/spec/cuco.plug.v3 点击 查看属性和方法 可以看到接口信息,其中 Switch 是控制开关的接口,也是我们主要使用的。

...

Search your code using Sourcegraph

Recently I have figured out how to handle link rot problem using Recoll. Of course you can use it for code searching, but we can do better.

Another method for searching code is using Github, if you don’t mind it’s online. Searching your own code is also easy with syntax user:<username>. However I want to be faster.

Years ago I tried Sourcegraph. I do not remember why I gave up. Maybe it’s because I was not familiar with Docker. Now I am using Docker everyday, actuaaly docker-compose, so I decided to give it another try. After finishing writing the previous sentence, I remembered that months ago sourcegraph cloud can host your own code, so I gave up self-hosting.

...

悲智双运

看完汉洋的伤痕椅子

很多年前就知道信息不对称,看完文章居然回忆了好一会才又想到这个词。技术很重要,技术的扩散也很重要。

所以是不是别太执着当下的选择?毕竟有限的见识怎么可能让我们做出最完美的选择呢。

学习到一个新的佛教用语,悲智双运。

向 ChatGPT 请教,告知这是佛教中的一个重要概念,它包含了两个方面的修行:悲和智。

悲,或称为悲心,是指对众生的苦难和痛苦产生深切的同情心和关怀。它是一种无私的、无条件的爱和慈悲,不仅仅局限于个人的幸福,而是关心所有众生的福祉。通过培养悲心,佛教徒努力解除众生的痛苦,并帮助他们摆脱轮回的苦难。

智,或称为智慧,是指超越表面现象,深入理解事物真实本性的能力。它是通过反思和观察,超越迷惑和糊涂的认知,认识到事物的真实性质和宇宙的本质。智慧帮助人们认识到所有事物都是无常、无我和苦的,从而超越执着和執著,追求解脱和智慧的境界。

悲智双运强调慈悲和智慧的双重修行,认为这两方面的修行是相辅相成的。悲心促使佛教徒关心他人并帮助他们,而智慧帮助佛教徒认识到如何最有效地帮助众生。只有通过悲心和智慧的双重修行,佛教徒才能实现自己的解脱和成佛,并最大限度地利益他人。悲智双运是佛教修行的核心理念之一,也是追求智慧与慈悲的佛教徒的目标之一。

In English, the concept of “悲智双运” can be expressed as the “twin cultivation of compassion and wisdom” or the “practice of compassion and wisdom in tandem.”

Compassion refers to the deep sympathy and concern for the suffering of all beings, extending beyond personal happiness. It is an altruistic and unconditional love and compassion that seeks to alleviate the suffering of others and help them transcend the cycle of suffering.

...

Obsidian 同步方案

Obsidian 是一款优秀的双链笔记软件,这里不多做介绍,能搜索到这篇文章的读者应该对此有了解。 我的笔记使用历程非常久远了,简单而不完全的回忆包括:Evernote、vimwiki、simplenote、onenote 、notion、roam research、logseq、obsidian。这些笔记软件都有各自的优势,但是目前我使用的是 Obsidian。

在桌面的使用场景下,使用 Dropbox 同步可以满足 Windows、Ubuntu、MacOS 三个平台的同步需求。 但是移动端 iOS 场景下,由于 iOS 的机制问题,Dropbox 同步无法获得好的体验。下面整理相关同步方案, 供读者备选。先后顺序表示优先级。

官方同步服务 Obsidian Sync #

官方链接 <obsidian.md/sync>

除了贵没有什么缺点,正常用户年付价格 8 USD/month,学生年付价格6折即 4.8 USD/month。早鸟用户 年付价格5折即 4 USD/month。

一个降低费用的方法是合租,因为一个 Obsidian Sync 付费账可以建立5个 remote vault (< https://help.obsidian.md/Obsidian+Sync/Limitations>) 每个 vault 可设置独立的密码 ( https://help.obsidian.md/Obsidian+Sync/Set+up+Obsidian+Sync ) 因此不用担心你的数据泄漏。 但是账户密码公开,每个成员均有权限删除仓库、删除账户、修改账户邮箱及密码,以上风险后果是损失一年的订阅费用,但是数据是安全的。相关信息可参考参考链接部分中的论坛合租讨论。 以及淘宝/闲鱼中也有相关车位出售。

rev-obsidian-sync 官方同步服务的逆向实现 #

来自高中生 @acheong08 大神的逆向实现。

相关链接

livesync #

https://github.com/vrtmrz/obsidian-livesync

...

使用 chatGPT 编写自动添加 beancount balance 断言语句

我使用 beancount 记账流程中的有一步是这样的,将每张信用卡的账单日添加到滴答清单中,每月重复。 每当到达账单日时,提醒我在 beancount 文件中添加一条对应帐目的 balance 断言语句,由于大部分信用卡 的出账是有滞后的,所以该balance断言通常需要同时加上!标记,便于后续账单出来后修改。

这个过程是比较机械的,所以我想到了使用 chatGPT 来自动化这个过程,这样我只需要在出账后手动更新自动添加 的断言语句,将金额修改为正确的还款金额,同时去除!标记。最终的脚本如下。

import datetime

def add_balance_statement(ledger_path, account, date, balance, currency):
    with open(ledger_path, 'a') as file:
        file.write(f"{date} balance {account} {balance} {currency}\n")

def auto_add_balance_statements(ledger_path, credit_cards):
    today = datetime.date.today()
    for card in credit_cards:
        bill_date = card['bill_date']
        accounts = card['accounts']
        balance = card['balance']
        currency = card['currency']
        if today.day == bill_date:
            for account in accounts:
                add_balance_statement(ledger_path, account, today, balance, currency)
                print(f"Balance statement added for {account} on {today}.")

# Specify the path to your Beancount ledger file
ledger_file_path = "<ledger_path>"

# Specify your credit card details (bill date, accounts, balance, and currency)
credit_cards = [
    {
        'bill_date': 1,  # Example: 1st of the month
        'accounts': [
            {'account': 'Assets:CreditCards:Card1:Account1', 'currency': 'USD'},  # Example: Account1 for Card1 with USD currency
            {'account': 'Assets:CreditCards:Card1:Account2', 'currency': 'EUR'},  # Example: Account2 for Card1 with EUR currency
        ],
        'balance': 1000.00,  # Example: Current balance for Card1
        'currency': 'USD'  # Example: Currency for Card1
    },
    {
        'bill_date': 15,  # Example: 15th of the month
        'accounts': [
            {'account': 'Assets:CreditCards:Card2:Account1', 'currency': 'USD'},  # Example: Account1 for Card2 with USD currency
            {'account': 'Assets:CreditCards:Card2:Account2', 'currency': 'GBP'},  # Example: Account2 for Card2 with GBP currency
        ],
        'balance': 2000.00,  # Example: Current balance for Card2
        'currency': 'USD'  # Example: Currency for Card2
    },
    # Add more credit card details as needed
]

# Call the function to automatically add balance statements
auto_add_balance_statements(ledger_file_path, credit_cards)

对于有兴趣的读者,可以看我和 chatgpt 的几轮对话。

...

MiniFlux Starred as Feed

Miniflux 是一个非常好用的 RSS 自托管方案,支持自建,支持多种客户端,支持多种订阅方式。 最近由于在折腾 Archivebox,需要将 Miniflux 中的 Starred Feed 作为一个 Feed 输出,以便于 导入星标条目到 Archivebox。 Miniflux 本身并不支持这个功能,但是其提供了 API,可以比较简单的导出 Starred 内容。

备选方案 #

如果是自己使用 Python 写的话,可以利用 https://github.com/miniflux/python-client 这个库,配合 feedgen 也能写个大概的,核心代码大概如下:

import miniflux
from feedgen.feed import FeedGenerator

client = miniflux.Client("https://miniflux.example.com", api_key="api_key")
entries = client.get_entries(starred=True, limit=50)

def create_rss_page(data):
    fg = FeedGenerator()
    fg.title('Miniflux Starred Feed')
    fg.link(href='https://miniflux.wogong.net', rel='self')
    fg.language('en')
    fg.description('Miniflux Starred Feed')

    for entry in data['entries']:
        fe = fg.add_entry()
        fe.id(entry['id'])
        fe.title(entry['title'])
        fe.link(href=entry['url'])
        fe.description('nothing')
        fe.author(name=entry['author'])
        fe.pubDate(entry['published_at'])

    rss_feed = fg.rss_str(pretty=True)
    fg.rss_file('rss.xml')
    return rss_feed

但是本着不自己造轮子的原则,找到了一些现成的工具,例如

...

Clash 作为网关的透明代理(更新)

距离上一篇介绍该主题的文章已经过去了接近三年,[Clash 作为网关的透明代理]({% post_url 2020-11-27-clash-transparent-proxy %}) 中间使用到的方案其实多次变更,例如使用了很长一段时间 的 shellclash,这个方案胜在省心,可以直接在支持的 路由器上部署,但是内核更新缓慢,作者对配置加了很多自定义设置,虽然出发点是为了方便大部分小白用户,但是 严重降低了自定义的能力。而且默认的一些设定大概率会导致 DNS 泄漏问题,关于这个话题可以参考 不良林的相关视频。这是不可接受的,因此前段时间又回归到使用 PVE 上虚拟机的方案。

简单摸索了一下最新方案发现 redir-host 模式已经被 Clash 官方放弃,不建议再使用。 TProxy 模式当然 没啥问题,但是毕竟得自己处理 iptables 规则。在没有性能瓶颈的情况下,更推荐使用 tun 模式,可以自动 处理路由等问题。下面简单介绍一下相关配置。

首先,在网关机器上打开 ipv4 转发, echo net.ipv4.ip_forward=1 >> /etc/sysctl.conf && sysctl -p

其次 Clash 配置文件头部添加如下

tun:
  enable: true
  stack: system # or gvisor
    #dns-hijack:
    #    - any:53
    #    - tcp://any:53
  auto-route: true
  auto-detect-interface: true
dns:
  enable: true
  ipv6: false
  listen: 0.0.0.0:53
  enhanced-mode: fake-ip       # redir-host or fake-ip
  fake-ip-range: 198.18.0.1/16    # Fake IP addresses pool CIDR
  use-hosts: true                 # lookup hosts and return IP record
  nameserver:
    - 114.114.114.114

最后在局域网的 DHCP 服务器设置网关为该机器 IP 即可,也可以手动在希望走代理机器的网关设置未该机器 IP。

...

用于 beancount 快速记账的 Telegram Bot

当年从随手记迁移到桌面记账方式(Excel/GnuCash/Beancount)后,确实有一段时间的不适应。 后来实在没有找到好用的移动端记账 APP,同时也适应了桌面记账,遂被驯化认为不需要在移动场景 记账。Costflow 出来之后没有第一时间尝试的原因也在于此,使用一段时间基于 costflow 语法 的 Telegram 机器人之后,发现经常是想要的账户没有配置,导致使用频率并不高。

前段时间的某一天突然意识到,为什么要提前配置账户信息呢?账户信息全部都在账本文件中,直接 查询账本文件不就可以避免冷启动的问题么。遂自己开坑写了一个新的记账机器人 beancount-bot

使用一月有余,今天完善了一下相关功能,更新了文档和使用例子。下面是几点简要说明:

  1. 适合手动记账党 :D
  2. 适合有自己服务器的人(境内服务器需要配置代理),部署在本地 NAS 上也是可行的
  3. 不兼容 costflow 语法,不需要账户信息的配置,账户的匹配是读取账本文件,类似编辑器的账户补全

在这里分享给大家,希望可以节省一点记账/对账的时间,有兴趣的欢迎尝试。

GitHub notification cannot clear bug

A few days ago I received a new type of spam email. Basically they create a GitHub repo and then spam everyone they want in the issues by @ them. Of course this gets banned after being reported. I do not do anything because I think someone else will do the reporting work.

Days later, when I log in to GitHub, I notice that there is a dot in the notification box, which means that there are unread notifications. So I tried to mark all notifications as read. The problem is that the spam notifications refuse to be deleted. Why is that? After checking I found that the spam repo has been deleted, maybe by GitHub. I tried everything in the Wed UI but failed.

...

在 cron/systemd timer 任务中的 git 认证

本文回答如何在 systemd timer 任务或者 cron 任务中进行 git 认证,方便进行 git pull/push 操作。

首先,不推荐 ssh-key 方式,不推荐,因为安全性和粒度控制不够。设置无 passphrase 的私钥(不安全),无法分 repo 控制权限。

推荐使用 https 配合 GitHub Personal Access Token 的方式,主要使用 gitcredentials - Providing usernames and passwords to Git,参考文档链接 https://git-scm.com/docs/gitcredentialshttps://git-scm.com/book/en/v2/Git-Tools-Credential-Storage

首先在 https://github.com/settings/apps 生成 Personal Access Token (PAT),建议使用细粒度的 token,降低泄露 token 的损失。

其次在需要操作的 repo 根目录进行设置

# 使用文件的方式储存认证信息
git config --local credential.helper store
# 使用路径来区分不同的认证信息
git config --local credential.useHttpPath true

设置完毕后手动操作一次,保存好 repo 的认证信息即可,认证信息储存在 ~/.git-credential.