├── .gitignore
├── README.md
├── airplay
└── install.sh
├── aria2
├── aria2.conf
└── tracklist.sh
├── backup
├── backup.sh
└── install.sh
├── dingdang
├── .dingdang
│ ├── pq.pmdl
│ ├── profile.yml
│ └── 佩奇.pmdl
└── install.sh
├── docker-containers
├── kodbox
│ ├── README.md
│ ├── app
│ │ ├── Dockerfile
│ │ ├── entrypoint.sh
│ │ ├── initdb.d
│ │ │ └── init.sql
│ │ ├── kodbox_admin_password.txt
│ │ ├── kodbox_admin_user.txt
│ │ ├── mysql_db.txt
│ │ ├── mysql_password.txt
│ │ ├── mysql_user.txt
│ │ ├── php-fpm.conf
│ │ └── setting_user.example
│ ├── docker-compose.yml
│ ├── install.sh
│ └── web
│ │ ├── conf.d
│ │ └── kodbox.conf
│ │ ├── nginx.conf
│ │ └── sslcerts
│ │ ├── tls.crt
│ │ └── tls.key
└── kode-syncting-webdav
│ └── install.sh
├── everyday_wechat
└── install.sh
├── frpc
├── frpc
├── frpc.ini
├── frpc_180704.ini
├── install.sh
└── monitor.sh
├── homeassistant
├── .homeassistant
│ ├── automations.yaml
│ ├── configuration.yaml
│ ├── custom_components
│ │ ├── media_player
│ │ │ └── vlc.py
│ │ ├── notify
│ │ │ ├── .alert_over.py.swx
│ │ │ └── alert_over.py
│ │ ├── sensor
│ │ │ ├── PhicommTokenGetter.py
│ │ │ ├── heweather.py
│ │ │ ├── heweather_hourlyforecast.py
│ │ │ └── lifesuggestion.py
│ │ ├── switch
│ │ │ └── phicomm_dc1m.py
│ │ ├── tts
│ │ │ └── baidu.py
│ │ └── weather
│ │ │ └── heweather_forecast.py
│ ├── customize.yaml
│ ├── groups.yaml
│ ├── packages
│ │ ├── cloudmusic.yaml
│ │ ├── heweather.yaml
│ │ ├── my_switch.yaml
│ │ ├── phicomm_dc1m.yaml
│ │ ├── suggest.yaml
│ │ ├── switch_group.yaml.bak
│ │ └── weather.yaml
│ ├── panels
│ │ └── cloudmusic.html
│ ├── scripts.yaml
│ ├── secrets.yaml
│ └── www
│ │ ├── custom_ui
│ │ ├── state-card-custom-ui-es5.html
│ │ ├── state-card-custom-ui-es5.html.gz
│ │ ├── state-card-custom-ui.html
│ │ └── state-card-custom-ui.html.gz
│ │ └── music
│ │ ├── cache
│ │ └── index.html
│ │ ├── css
│ │ ├── jquery.mCustomScrollbar.min.css
│ │ ├── player.css
│ │ └── small.css
│ │ ├── images
│ │ ├── airplayer.png
│ │ ├── album_cover_player.png
│ │ ├── go.png
│ │ ├── history.png
│ │ ├── icon_list_menu.png
│ │ ├── loading.gif
│ │ ├── player.png
│ │ ├── player_cover.png
│ │ └── wave.gif
│ │ ├── index.html
│ │ ├── js
│ │ ├── airplay.js
│ │ ├── ajax.js
│ │ ├── background-blur.min.js
│ │ ├── functions.js
│ │ ├── jquery.mCustomScrollbar.concat.min.js
│ │ ├── jquery.min.js
│ │ ├── js-yaml.min.js
│ │ ├── lyric.js
│ │ ├── musicList.js
│ │ ├── player.js
│ │ └── plug-in.min.js
│ │ └── plugns
│ │ ├── killie
│ │ ├── img
│ │ │ ├── 360.jpg
│ │ │ ├── chrome.jpg
│ │ │ ├── firefox.jpg
│ │ │ ├── opera.jpg
│ │ │ ├── safari.jpg
│ │ │ └── top.jpg
│ │ └── index.html
│ │ └── layer
│ │ ├── layer.js
│ │ ├── mobile
│ │ ├── layer.js
│ │ └── need
│ │ │ └── layer.css
│ │ └── skin
│ │ └── default
│ │ ├── icon-ext.png
│ │ ├── icon.png
│ │ ├── layer.css
│ │ ├── loading-0.gif
│ │ ├── loading-1.gif
│ │ └── loading-2.gif
└── install.sh
├── init.sh
├── install.sh
├── kodi
├── install.sh
├── kodi.desktop
├── readme.md
└── 插件库
│ ├── plugin.video.115_2.1.5.zip
│ ├── plugin.video.uwc-1.1.63.zip
│ ├── plugin.video.youporngay-0.3.zip
│ ├── repository.adulthideout-1.0.1.zip
│ ├── repository.colossus-999.999.9.zip
│ ├── repository.hdpfans.xbmc-addons-chinese.zip
│ ├── repository.xbmc-addons-chinese-1.2.1.zip
│ ├── repository.xbmcadult-1.0.7.zip
│ ├── resource.language.zh_cn-1.0.3.zip
│ └── script.module.beautifulsoup-3.2.1.zip
├── musicbox
├── autoplay.sh
└── install.sh
├── node_web
├── app.js
├── package.json
└── shell
│ ├── frpc.sh
│ └── play.sh
├── npc
├── conf
│ ├── multi_account.conf
│ └── npc.conf
├── install.sh
└── npc
├── overlayfs
├── .bashrc
├── overlayRoot.sh
└── readme.md
├── php_nginx_kode
├── default
├── install.sh
└── kodexplorer4.25.zip
├── qbittorrent
└── install.sh
├── rclone
├── copy_local_to_onedrive.sh
└── readme.md
├── samba
├── install.sh
└── smb.conf
├── sources.list
├── startup
├── init.d
│ └── my_boot
├── install.sh
├── rc.local
├── startup.sh
├── startup190519.sh
└── startup_181206.sh
├── syncthing
└── install.sh
├── usbmount
├── my_usb.sh
└── usb_mount.sh
├── vimrc
├── webssh
├── install.sh
├── run.py
└── wssh
├── zsh
└── .zshrc
└── 树莓派wifi助手
├── README.md
└── install.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | __pycache__
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 树莓派3p配置安装脚本
2 | 刷机后解压到`/home/pi/pi3-script/`下执行
3 | # 说明
4 | * init.sh 初始化配置脚本,可以修改后自由定制
5 |
--------------------------------------------------------------------------------
/airplay/install.sh:
--------------------------------------------------------------------------------
1 | #参考:http://ju.outofmemory.cn/entry/325107 https://zhuanlan.zhihu.com/p/21492887?refer=tuijiankan
2 |
3 | sudo apt-get install libao-dev libssl-dev git avahi-utils libwww-perl
4 | sudo apt-get install libcrypt-openssl-rsa-perl libio-socket-inet6-perl libmodule-build-perl
5 |
6 | git clone https://github.com/njh/perl-net-sdp.git
7 | cd perl-net-sdp
8 | perl Build.PL
9 | ./Build
10 | ./Build test
11 | sudo ./Build install
12 | cd ..
13 |
14 | git clone https://github.com/abrasive/shairport.git
15 | cd shairport
16 | make
--------------------------------------------------------------------------------
/aria2/aria2.conf:
--------------------------------------------------------------------------------
1 | #允许rpc
2 | enable-rpc=true
3 | #允许所有来源, web界面跨域权限需要
4 | rpc-allow-origin-all=true
5 | #允许非外部访问
6 | rpc-listen-all=true
7 | #RPC端口, 仅当默认端口被占用时修改
8 | #rpc-listen-port=6800
9 | check-certificate=false
10 | enable-dht=true
11 | bt-enable-lpd=true
12 | enable-peer-exchange=true
13 | #文件保存路径, 默认为当前启动位置
14 | dir=/media/pi/DA18-EBFA
15 | bt-tracker=udp://tracker.coppersurfer.tk:6969/announce,udp://tracker.open-internet.nl:6969/announce,udp://tracker.leechers-paradise.org:6969/announce,udp://tracker.openbittorrent.com:80/announce,udp://exodus.desync.com:6969/announce,udp://9.rarbg.to:2710/announce,udp://9.rarbg.me:2710/announce,udp://tracker.internetwarriors.net:1337/announce,udp://tracker.opentrackr.org:1337/announce,http://tracker.opentrackr.org:1337/announce,udp://tracker.torrent.eu.org:451/announce,udp://tracker.tiny-vps.com:6969/announce,udp://bt.xxx-tracker.com:2710/announce,udp://tracker.cyberia.is:6969/announce,udp://thetracker.org:80/announce,udp://denis.stalker.upeer.me:6969/announce,udp://open.demonii.si:1337/announce,udp://explodie.org:6969/announce,http://explodie.org:6969/announce,http://open.acgnxtracker.com:80/announce,udp://ipv4.tracker.harry.lu:80/announce,udp://tracker.supertracker.net:1337/announce,udp://tracker.iamhansen.xyz:2000/announce,udp://tracker.filepit.to:6969/announce,udp://tracker.filemail.com:6969/announce,udp://torrentclub.tech:6969/announce,udp://retracker.netbynet.ru:2710/announce,udp://retracker.lanta-net.ru:2710/announce,udp://retracker.baikal-telecom.net:2710/announce,udp://tracker.trackton.ga:7070/announce,udp://tracker.novg.net:6969/announce,https://tracker.fastdownload.xyz:443/announce,https://t.quic.ws:443/announce,http://tracker.novg.net:6969/announce,http://opentracker.h4ck.me:6969/announce,http://open.trackerlist.xyz:80/announce,http://open.acgtracker.com:1096/announce,http://gwp2-v19.rinet.ru:80/announce,udp://tracker.uw0.xyz:6969/announce,udp://tracker.tvunderground.org.ru:3218/announce,udp://tracker.gbitt.info:80/announce,https://tracker.gbitt.info:443/announce,http://vps02.net.orel.ru:80/announce,http://tracker.tvunderground.org.ru:3218/announce,http://tracker.gbitt.info:80/announce,udp://zephir.monocul.us:6969/announce,udp://tracker.kamigami.org:2710/announce,udp://retracker.maxnet.ua:80/announce,udp://retracker.akado-ural.ru:80/announce,udp://carapax.net:6969/announce,http://mail2.zelenaya.net:80/announce,http://carapax.net:6969/announce,udp://home.penza.com.ru:6969/announce,http://tracker.moxing.party:6969/announce,http://torrent.nwps.ws:80/announce,udp://tracker.nyaa.uk:6969/announce,udp://tracker.moeking.me:6969/announce,udp://retracker.sevstar.net:2710/announce,udp://pubt.in:2710/announce,udp://bt.dy20188.com:80/announce,https://tracker.vectahosting.eu:2053/announce,https://tracker.parrotsec.org:443/announce,http://tracker.bz:80/announce,http://tracker.bt4g.com:2095/announce,http://t.nyaatracker.com:80/announce,http://retracker.sevstar.net:2710/announce,udp://packages.crunchbangplusplus.org:6969/announce,udp://chihaya.toss.li:9696/announce,https://1337.abcvg.info:443/announce,http://tracker.torrentyorg.pl:80/announce,http://t.acg.rip:6699/announce,http://share.camoe.cn:8080/announce,http://retracker.mgts.by:80/announce,http://bt-tracker.gamexp.ru:2710/announce,udp://tracker4.itzmx.com:2710/announce,http://tracker4.itzmx.com:2710/announce,http://tracker3.itzmx.com:6961/announce,http://tracker2.itzmx.com:6961/announce,http://tracker1.itzmx.com:8080/announce
16 |
--------------------------------------------------------------------------------
/aria2/tracklist.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #readme http://www.senra.me/solutions-to-aria2-bt-metalink-download-slowly
3 | killall aria2c
4 | path=/home/pi/pi3-script/aria2/aria2.conf
5 | list=`wget -qO- https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_all.txt|awk NF|sed ":a;N;s/\n/,/g;ta"`
6 | if [ -z "`grep "bt-tracker" ${path}`" ]; then
7 | sed -i '$a bt-tracker='${list} ${path}
8 | echo add......
9 | else
10 | sed -i "s@bt-tracker.*@bt-tracker=$list@g" ${path}
11 | echo update......
12 | fi
13 | aria2c --conf-path=/home/pi/pi3-script/aria2/aria2.conf -D
--------------------------------------------------------------------------------
/backup/backup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #备份存放路径
3 | TARGET_DIR=/media/pi/DA18-EBFA/pi-backup
4 | #要备份的文件列表
5 | BACKUP_FOLDERS=(
6 | '/home/pi/pi3-script/frpc'
7 | '/home/pi/pi3-script/startup'
8 | '/home/pi/.homeassistant/'
9 | '/home/pi/www/'
10 | )
11 | #排除的文件列表
12 | EXCLUDES=(
13 | '*/.cloud'
14 | '*/.storage'
15 | '*/deps'
16 | '*/.uuid'
17 | '*/home-assistant_v2.db'
18 | '*/tts'
19 | '*/tts'
20 | '*/__pycache__'
21 | '*/*.log'
22 | '*/backup'
23 | '*/temp'
24 | '*/session'
25 | '*/recycle_kod'
26 | )
27 |
28 |
29 | ERROR_LOG_FILE=./backup.log
30 | mkdir -p ${TARGET_DIR}
31 | DIRS=''
32 | for i in "${BACKUP_FOLDERS[@]}"; do
33 | DIRS="${DIRS} ${i}"
34 | done
35 | excludelist=''
36 | #excludelist="--exclude */.uuid --exclude */home-assistant_v2.db --exclude */tts --exclude */__pycache__ --exclude */*.log"
37 | for j in "${EXCLUDES[@]}"; do
38 | excludelist="${excludelist} --exclude ${j}"
39 | done
40 | echo $(date "+%Y-%m-%d %H:%M:%S"): backup data to ${TARGET_DIR}/backup-$(date +%Y%m%d).tar.gz start >> ${ERROR_LOG_FILE}
41 | tar czPvf ${TARGET_DIR}/backup-$(date +%Y%m%d).tar.gz ${excludelist} ${DIRS}
42 | echo $(date "+%Y-%m-%d %H:%M:%S"): "backup data end" >> ${ERROR_LOG_FILE}
43 |
44 | #删除改文件夹下超过30天的文件
45 | find ${TARGET_DIR} -mtime +30 -name "*.tar.gz" -exec rm -rf {} \;
46 |
--------------------------------------------------------------------------------
/backup/install.sh:
--------------------------------------------------------------------------------
1 | basepath=$(cd `dirname $0`; pwd)
2 | ln -s $basepath/backup.sh ~/backup.sh
3 | ~/backup.sh
4 |
--------------------------------------------------------------------------------
/dingdang/.dingdang/pq.pmdl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/dingdang/.dingdang/pq.pmdl
--------------------------------------------------------------------------------
/dingdang/.dingdang/profile.yml:
--------------------------------------------------------------------------------
1 | robot_name: 'DINGDANG' # 必须使用大写
2 | robot_name_cn: '佩奇'
3 | first_name: '小波'
4 | last_name: '朱'
5 | timezone: HKT
6 | location: '上海'
7 |
8 | # 是否接入微信
9 | wechat: true
10 |
11 | # 当微信发送语音时,是直接播放语音还是执行语音命令?
12 | # true:直接播放
13 | # false:执行语音命令(只支持百度STT,其他两种STT识别不准)
14 | wechat_echo: false
15 |
16 | # 除了自己之外,还能响应 echo 指令的好友微信名单
17 | # 如果填写 ['ALL'] 表示响应所有微信好友
18 | # 如果填写 [] 表示不响应任何好友
19 | wechat_echo_text_friends: ['ALL']#['小Q', 'HaHack']
20 |
21 | # 除了自己之外,还能直接播放语音的好友微信名单
22 | # 如果填写 ['ALL'] 表示播放所有微信好友的语音
23 | # 如果填写 [] 表示不播放任何好友的语音
24 | wechat_echo_voice_friends: ['任性又如何']
25 |
26 | # 当有邮件时,是否朗读邮件标题
27 | read_email_title: true
28 |
29 | # 当内容过长(> 200个字)时,是否继续朗读
30 | # true:读
31 | # false:改为发送内容
32 | read_long_content: false
33 |
34 | # 最长朗读内容(仅当 read_long_content 为 false 时有效)
35 | max_length: 200
36 |
37 | # 是否使用邮箱发送长内容而不是微信
38 | prefers_email: false
39 |
40 | # 勿扰模式,该时间段内不执行通知检查
41 | do_not_bother:
42 | enable: true # 开启勿扰模式
43 | since: 23 # 开始时间
44 | till: 9 # 结束时间,如果比 since 小表示第二天
45 |
46 | # 语音合成服务配置
47 | # 可选值:
48 | # baidu-tts - 百度语音识别
49 | # iflytek-tts - 讯飞语音合成
50 | # ali-tts - 阿里语音合成
51 | # google-tts - 谷歌语音合成
52 | tts_engine: baidu-tts
53 |
54 | # STT 服务配置
55 | # 可选值:
56 | # sphinx - pocketsphinx离线识别引擎(需训练,参考修改唤醒词教程)
57 | # baidu-stt - 百度在线语音识别
58 | # iflytek-stt - 讯飞语音识别
59 | # ali-stt - 阿里语音识别
60 | # google-stt - 谷歌语音合成
61 | stt_engine: baidu-stt
62 |
63 | # 离线唤醒 SST 引擎
64 | # 可选值:
65 | # sphinx - pocketspinx离线唤醒
66 | # snowboy-stt - snowboy离线唤醒
67 | stt_passive_engine: snowboy-stt
68 |
69 | # pocketsphinx 唤醒SST引擎(默认)
70 | pocketsphinx:
71 | fst_model: '/home/pi/g014b2b/g014b2b.fst'
72 |
73 | # snowboy 唤醒SST引擎(可选)
74 | # https://snowboy.kitt.ai/dashboard
75 | snowboy:
76 | model: '/home/pi/.dingdang/pq.pmdl' # 唤醒词模型
77 | sensitivity: "0.5" # 敏感度
78 |
79 | # 百度语音服务
80 | # http://yuyin.baidu.com/
81 | baidu_yuyin:
82 | api_key: 'XtR74Qq3EvCRQNiLT7fHGna1'
83 | secret_key: 'XMeYTwjGOI4k6hC8PkTqM9nRew3Ehszt'
84 | per: 0 # 发音人选择 0:女生;1:男生;3:度逍遥;4:度丫丫
85 |
86 | # 讯飞语音服务
87 | # api_id 及 api_key 需前往
88 | # http://aiui.xfyun.cn/webApi
89 | # 注册获取(注意创建的是WebAPI应用),仅使用语音合成无需注册
90 | # 然后将主板的ip地址添加进ip白名单(建议使用中转服务器的ip地址 101.132.139.80)
91 | iflytek_yuyin:
92 | api_id: '填写你的讯飞应用的Api ID'
93 | api_key: '填写你的讯飞应用的Api Key' # 没看到这个说明不是注册的WebAPI应用,请改注册个WebAPI应用
94 | vid: '67100' #语音合成选项: 60120为小桃丸 67100为颖儿 60170为萌小新 更多音色见wiki
95 | url: 'http://api.musiiot.top/stt.php' # 白名单ip中转服务器(可选)
96 |
97 | # 阿里云语音
98 | # ak_id及ak_secret需前往
99 | # https://data.aliyun.com/product/nls
100 | # 注册获取
101 | ali_yuyin:
102 | ak_id: '填写你的阿里云应用的AcessKey ID'
103 | ak_secret: '填写你的阿里云应用的AcessKey Secret'
104 | voice_name: 'xiaoyun' #xiaoyun为女生,xiaogang为男生
105 |
106 | # 谷歌语音
107 | # api_key 的获取方式:
108 | # 1. Join the Chromium Dev group:
109 | # https://groups.google.com/a/chromium.org/forum/?fromgroups#!forum/chromium-dev
110 | # 2. Create a project through the Google Developers console:
111 | # https://console.developers.google.com/project
112 | # 3. Select your project. In the sidebar, navigate to "APIs & Auth." Activate
113 | # the Speech API.
114 | # 4. Under "APIs & Auth," navigate to "Credentials." Create a new key for
115 | # public API access.
116 | google_yuyin:
117 | language: 'zh-CN'
118 | api_key: ''
119 |
120 | # 聊天机器人
121 | # 可选值:
122 | # tuling - 图灵机器人
123 | # emotibot - 小影机器人
124 | robot: tuling
125 |
126 | # 图灵机器人
127 | # http://www.tuling123.com
128 | tuling:
129 | tuling_key: 'c380ed8f2880443c84892ace36ba6bad'
130 |
131 | # 小影机器人
132 | # http://botfactory.emotibot.com/
133 | emotibot:
134 | appid: '填写你的 emotibot appid'
135 | active_mode: true # 是否主动说更多点话
136 |
137 | # 邮箱
138 | # 如果使用网易邮箱,还需设置允许第三方客户端收发邮件
139 | email:
140 | enable: true
141 | address: 'ethanzhu_zxb@163.com'
142 | password: 'zGrTth66' # 如果是网易邮箱,须填写应用授权密码而不是登录密码!
143 | smtp_server: 'smtp.163.com'
144 | smtp_port: '25' # 这里填写非SSL协议端口号
145 | imap_server: 'imap.163.com'
146 | imap_port: '143' # 这里填写非SSL协议端口号
147 |
148 |
149 | # 拍照
150 | # 需接入摄像头才能使用
151 | camera:
152 | enable: true
153 | dest_path: "/home/pi/camera" # 保存目录
154 | quality: 5 # 成像质量(0~100)
155 | vertical_flip: true # 竖直翻转
156 | horizontal_flip: false # 水平翻转
157 | count_down: 3 # 倒计时(秒),仅当开启倒计时时有效
158 | sendToUser: true # 拍完照是否发送到邮箱/微信
159 | sound: true # 是否有拍照音效
160 | usb_camera: true # 是否使用USB摄像头(默认是树莓派5MP摄像头)
161 |
162 |
163 | #######################
164 | # 第三方插件的配置
165 | #######################
166 |
167 | # 在这里放第三方插件的配置
168 | # https://github.com/wzpan/dingdang-contrib
169 | # 网易音乐
170 | netease_music:
171 | account: 'ethanzhu_zxb@163.com' # 只支持手机账户
172 | password: 'bb900102'
173 | report: true # 是否播报即将播放的音乐
174 | local_path: '/home/pi/Music/' # 本地音乐目录
175 | local_default: True # 默认播放本地音乐
176 | # 新闻头条
177 | # 聚合数据新闻头条API
178 | # https://www.juhe.cn/docs/api/id/235
179 | headline_news:
180 | key: 'AppKey'
181 |
182 | # Email My PC
183 | emailmypc:
184 | pc_email: '764724624@qq.com'
185 | button: '自定义快捷键'
186 | cmd: '自定义指令'
187 |
188 | # WOL启动
189 | wol:
190 | ip: '192.168.1.255' #局域网广播地址或指定电脑IP地址
191 | mac: '00-E0-70-6B-40-33'
192 | # 天气
193 | # 使用心知天气的接口
194 | # https://www.seniverse.com/
195 | weather:
196 | key: 'muzyqkhksgdusakq'
197 | location: '上海'
--------------------------------------------------------------------------------
/dingdang/.dingdang/佩奇.pmdl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/dingdang/.dingdang/佩奇.pmdl
--------------------------------------------------------------------------------
/dingdang/install.sh:
--------------------------------------------------------------------------------
1 |
2 | #安装dingdang参考:https://github.com/dingdang-robot/dingdang-robot/wiki/install
3 |
4 | cp ./dingdnag /home/pi/.dingdang/
5 |
6 | # 以下代码可以放到开机自启动shell脚本中
7 | # 叮当语音
8 | #echo ...启动叮当语音.. >> ./startup.log
9 | sh /home/pi/dingdang/launcher/dingdang-launcher-user.sh
10 |
--------------------------------------------------------------------------------
/docker-containers/kodbox/README.md:
--------------------------------------------------------------------------------
1 | ## 简介
2 | 网络上基于 docker 的 kodbox 镜像多为 x86 平台所构建的,本项目支持在 aarch64 的平台和 x86 平台构建,该项目的初衷是在树梅派上部署 kodbox 。但本文迟迟未发布,截至本文发布日, `KodCloud-dev` 已 于12 天前发布了一版具有 Dockerfile 构建的项目,见最后的参考,读者可自行测试吧。
3 |
4 | ## 文件结构简要说明
5 |
6 | ```bash
7 | |-- kodbox
8 | |-- app # kodbox镜像构建及初始化脚本
9 | |-- Dockerfile # kodbox 镜像构建文件
10 | |-- entrypoint.sh
11 | |-- php-fpm.conf # root用户运行的php-fpm配置文件
12 | |-- initdb.d # 数据库初始化脚本
13 | |-- mysql_db.txt
14 | |-- mysql_password.txt # 数据库密码,请修改
15 | |-- mysql_user.txt
16 | |-- setting_user.example
17 | |-- web
18 | |-- conf.d # nginx 配置目录
19 | |-- nginx.conf # nginx 主配置文件,定义了日志记录格式
20 | |-- sslcerts # ssl 证书及密钥文件目录,替换为自己的
21 | |-- docker-compose.yml # 编排文件
22 | ```
23 |
24 | ## 快速使用
25 | ```bash
26 | git clone https://github.com/evling2020/kodbox.git
27 | docker-compose build
28 | docker-compose up -d
29 | ```
30 | ## 注意
31 | 如果想让kodbox具有root权限来操作磁盘文件,需要使用php-fpm.conf文件
32 |
33 |
34 | ## 参考
35 | - https://github.com/KodCloud-dev/docker
36 |
--------------------------------------------------------------------------------
/docker-containers/kodbox/app/Dockerfile:
--------------------------------------------------------------------------------
1 | # https://www.evling.me/
2 | FROM php:7.4-fpm-alpine3.12
3 |
4 | LABEL maintainer="evling2020@gmail.com"
5 | ENV KODBOX_VERSION=1.14
6 |
7 | # entrypoint.sh and cron.sh dependencies
8 | RUN echo @testing http://mirrors.ustc.edu.cn/alpine/edge/testing >> /etc/apk/repositories && \
9 | sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \
10 | echo /etc/apk/respositories && \
11 | apk update && apk upgrade &&\
12 | apk add --no-cache \
13 | imagemagick \
14 | ffmpeg \
15 | unzip \
16 | rsync \
17 | unrar \
18 | tzdata && \
19 | cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
20 | echo "Asia/Shanghai" > /etc/timezone
21 |
22 | # install the PHP extensions we need
23 | # see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html
24 | RUN set -ex; \
25 | \
26 | apk add --no-cache --virtual .build-deps \
27 | $PHPIZE_DEPS \
28 | autoconf \
29 | freetype-dev \
30 | icu-dev \
31 | libevent-dev \
32 | libjpeg-turbo-dev \
33 | libmcrypt-dev \
34 | libpng-dev \
35 | libmemcached-dev \
36 | libxml2-dev \
37 | libzip-dev \
38 | openldap-dev \
39 | pcre-dev \
40 | postgresql-dev \
41 | imagemagick-dev \
42 | libwebp-dev \
43 | gmp-dev \
44 | ; \
45 | \
46 | docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \
47 | docker-php-ext-configure ldap; \
48 | docker-php-ext-install -j "$(nproc)" \
49 | mysqli \
50 | bcmath \
51 | exif \
52 | gd \
53 | intl \
54 | ldap \
55 | opcache \
56 | pcntl \
57 | pdo_mysql \
58 | pdo_pgsql \
59 | zip \
60 | gmp \
61 | ; \
62 | \
63 | # pecl will claim success even if one install fails, so we need to perform each install separately
64 | pecl install APCu-5.1.18; \
65 | pecl install memcached-3.1.5; \
66 | pecl install redis-5.3.1; \
67 | pecl install imagick-3.4.4; \
68 | \
69 | docker-php-ext-enable \
70 | apcu \
71 | memcached \
72 | redis \
73 | imagick \
74 | ; \
75 | \
76 | runDeps="$( \
77 | scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \
78 | | tr ',' '\n' \
79 | | sort -u \
80 | | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
81 | )"; \
82 | apk del tzdata .build-deps
83 |
84 | # set recommended PHP.ini settings
85 | # see https://docs.nextcloud.com/server/12/admin_manual/configuration_server/server_tuning.html#enable-php-opcache
86 | RUN { \
87 | echo 'opcache.enable=1'; \
88 | echo 'opcache.interned_strings_buffer=8'; \
89 | echo 'opcache.max_accelerated_files=10000'; \
90 | echo 'opcache.memory_consumption=128'; \
91 | echo 'opcache.save_comments=1'; \
92 | echo 'opcache.revalidate_freq=1'; \
93 | echo 'post_max_size=10G'; \
94 | echo 'upload_max_filesize=10G'; \
95 | echo 'max_execution_time=3600'; \
96 | } > /usr/local/etc/php/conf.d/opcache-recommended.ini; \
97 | \
98 | echo 'apc.enable_cli=1' >> /usr/local/etc/php/conf.d/docker-php-ext-apcu.ini; \
99 | \
100 | echo 'memory_limit=512M' > /usr/local/etc/php/conf.d/memory-limit.ini; \
101 | \
102 | mkdir /var/www/data; \
103 | chown -R www-data:root /var/www; \
104 | chmod -R g=u /var/www
105 |
106 | VOLUME /var/www/html
107 |
108 | ADD setting_user.example /usr/src/kodbox/config/setting_user.example
109 | RUN set -ex; \
110 | apk add --no-cache --virtual .fetch-deps \
111 | bzip2 \
112 | gnupg \
113 | ; \
114 | \
115 | curl -fsSL -o kodbox.zip \
116 | "http://static.kodcloud.com/update/download/kodbox.${KODBOX_VERSION}.zip"; \
117 | export GNUPGHOME="$(mktemp -d)"; \
118 | unzip -d /usr/src/kodbox kodbox.zip; \
119 | cp /usr/bin/unrar /usr/src/kodbox/app/sdks/archiveLib/bin/rar; \
120 | sed -i "s/'chunkSize' => 0.5,/'chunkSize' => 5,/g" /usr/src/kodbox/config/setting.php;\
121 | gpgconf --kill all; \
122 | apk del .fetch-deps
123 |
124 | COPY entrypoint.sh /
125 | RUN chmod +x /entrypoint.sh
126 | ENTRYPOINT ["/entrypoint.sh"]
127 | CMD ["php-fpm","-R"] # as ROOT
128 |
--------------------------------------------------------------------------------
/docker-containers/kodbox/app/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -eu
3 |
4 | # version_greater A B returns whether A > B
5 | version_greater() {
6 | [ "$(printf '%s\n' "$@" | sort -t '.' -n -k1,1 -k2,2 -k3,3 -k4,4 | head -n 1)" != "$1" ]
7 | }
8 |
9 | # return true if specified directory is empty
10 | directory_empty() {
11 | [ -z "$(ls -A "$1/")" ]
12 | }
13 |
14 | run_as() {
15 | if [ "$(id -u)" = 0 ]; then
16 | su -p www-data -s /bin/sh -c "$1"
17 | else
18 | sh -c "$1"
19 | fi
20 | }
21 |
22 | # usage: file_env VAR [DEFAULT]
23 | # ie: file_env 'XYZ_DB_PASSWORD' 'example'
24 | # (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
25 | # "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
26 | file_env() {
27 | local var="$1"
28 | local fileVar="${var}_FILE"
29 | local def="${2:-}"
30 | local varValue=$(env | grep -E "^${var}=" | sed -E -e "s/^${var}=//")
31 | local fileVarValue=$(env | grep -E "^${fileVar}=" | sed -E -e "s/^${fileVar}=//")
32 | if [ -n "${varValue}" ] && [ -n "${fileVarValue}" ]; then
33 | echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
34 | exit 1
35 | fi
36 | if [ -n "${varValue}" ]; then
37 | export "$var"="${varValue}"
38 | elif [ -n "${fileVarValue}" ]; then
39 | export "$var"="$(cat "${fileVarValue}")"
40 | elif [ -n "${def}" ]; then
41 | export "$var"="$def"
42 | fi
43 | unset "$fileVar"
44 | }
45 |
46 | if expr "$1" : "apache2-foreground" 1>/dev/null; then
47 | if [ -n "${APACHE_DISABLE_REWRITE_IP+x}" ]; then
48 | a2disconf remoteip
49 | fi
50 | fi
51 |
52 | if expr "$1" : "apache2-foreground" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UPDATE:-0}" -eq 1 ]; then
53 | if [ -n "${REDIS_HOST+x}" ]; then
54 |
55 | echo "Configuring Redis as session handler"
56 | {
57 | echo 'session.save_handler = redis'
58 | # check if redis host is an unix socket path
59 | if [ "$(echo "$REDIS_HOST" | cut -c1-1)" = "/" ]; then
60 | if [ -n "${REDIS_HOST_PASSWORD+x}" ]; then
61 | echo "session.save_path = \"unix://${REDIS_HOST}?auth=${REDIS_HOST_PASSWORD}\""
62 | else
63 | echo "session.save_path = \"unix://${REDIS_HOST}\""
64 | fi
65 | # check if redis password has been set
66 | elif [ -n "${REDIS_HOST_PASSWORD+x}" ]; then
67 | echo "session.save_path = \"tcp://${REDIS_HOST}:${REDIS_HOST_PORT:=6379}?auth=${REDIS_HOST_PASSWORD}\""
68 | else
69 | echo "session.save_path = \"tcp://${REDIS_HOST}:${REDIS_HOST_PORT:=6379}\""
70 | fi
71 | } > /usr/local/etc/php/conf.d/redis-session.ini
72 | fi
73 |
74 | file_env MYSQL_SERVER
75 | file_env MYSQL_DATABASE
76 | file_env MYSQL_USER
77 | file_env MYSQL_PASSWORD
78 | file_env MYSQL_PORT
79 | file_env SESSION_TYPE
80 | file_env SESSION_HOST
81 | file_env SESSION_PORT
82 | file_env KODBOX_ADMIN_USER
83 | file_env KODBOX_ADMIN_PASSWORD
84 |
85 | MYSQL_PORT=${MYSQL_PORT:-3306}
86 | SESSION_TYPE=${SESSION_PORT:-redis}
87 | SESSION_PORT=${SESSION_PORT:-6379}
88 |
89 |
90 | if [ -n "${MYSQL_DATABASE+x}" ] && [ -n "${MYSQL_USER+x}" ] && [ -n "${MYSQL_PASSWORD+x}" ] && [ ! -f "/usr/src/kodbox/config/setting_user.php" ]; then
91 | cp /usr/src/kodbox/config/setting_user.example /usr/src/kodbox/config/setting_user.php
92 | sed -i "s/MYSQL_SERVER/${MYSQL_SERVER}/g" /usr/src/kodbox/config/setting_user.php
93 | sed -i "s/MYSQL_DATABASE/${MYSQL_DATABASE}/g" /usr/src/kodbox/config/setting_user.php
94 | sed -i "s/MYSQL_USER/${MYSQL_USER}/g" /usr/src/kodbox/config/setting_user.php
95 | sed -i "s/MYSQL_PASSWORD/${MYSQL_PASSWORD}/g" /usr/src/kodbox/config/setting_user.php
96 | sed -i "s/MYSQL_PORT/${MYSQL_PORT}/g" /usr/src/kodbox/config/setting_user.php
97 | touch /usr/src/kodbox/data/system/fastinstall.lock
98 |
99 | if [ -n "${KODBOX_ADMIN_USER+x}" ] && [ -n "${KODBOX_ADMIN_PASSWORD+x}" ]; then
100 | echo -e "ADM_NAME=${KODBOX_ADMIN_USER}\nADM_PWD=${KODBOX_ADMIN_PASSWORD}" >> /usr/src/kodbox/data/system/fastinstall.lock
101 | fi
102 | if [ -n "${SESSION_HOST+x}" ]; then
103 | sed -i "s/SESSION_TYPE/${SESSION_TYPE}/g" /usr/src/kodbox/config/setting_user.php
104 | sed -i "s/SESSION_HOST/${SESSION_HOST}/g" /usr/src/kodbox/config/setting_user.php
105 | sed -i "s/SESSION_PORT/${SESSION_PORT}/g" /usr/src/kodbox/config/setting_user.php
106 | else
107 | sed -i "s/SESSION_TYPE/file/g" /usr/src/kodbox/config/setting_user.php
108 | sed -i "s/SESSION_HOST/file/g" /usr/src/kodbox/config/setting_user.php
109 | fi
110 |
111 | fi
112 |
113 | # if version_greater "$image_version" "$installed_version"; then
114 | if directory_empty "/var/www/html"; then
115 | if [ "$(id -u)" = 0 ]; then
116 | rsync_options="-rlDog --chown www-data:root"
117 | else
118 | rsync_options="-rlD"
119 | fi
120 | # rsync $rsync_options --delete --exclude-from=/upgrade.exclude /usr/src/kodbox/ /var/www/html/
121 | rsync $rsync_options --delete /usr/src/kodbox/ /var/www/html/
122 | if [ -n "${KODBOX_ADMIN_USER+x}" ] && [ -n "${KODBOX_ADMIN_PASSWORD+x}" ]; then
123 | waiting_for_db
124 | php /var/www/html/index.php "install/index/auto"
125 | chown -R www-data:root /var/www
126 | fi
127 | else
128 | echo "KODBOX has been configured!"
129 | fi
130 | fi
131 |
132 | exec "$@"
133 |
--------------------------------------------------------------------------------
/docker-containers/kodbox/app/kodbox_admin_password.txt:
--------------------------------------------------------------------------------
1 | admin_PWD
2 |
--------------------------------------------------------------------------------
/docker-containers/kodbox/app/kodbox_admin_user.txt:
--------------------------------------------------------------------------------
1 | admin
2 |
--------------------------------------------------------------------------------
/docker-containers/kodbox/app/mysql_db.txt:
--------------------------------------------------------------------------------
1 | kodbox
2 |
--------------------------------------------------------------------------------
/docker-containers/kodbox/app/mysql_password.txt:
--------------------------------------------------------------------------------
1 | kodbox_PWD
2 |
--------------------------------------------------------------------------------
/docker-containers/kodbox/app/mysql_user.txt:
--------------------------------------------------------------------------------
1 | kodbox
2 |
--------------------------------------------------------------------------------
/docker-containers/kodbox/app/php-fpm.conf:
--------------------------------------------------------------------------------
1 | ;;;;;;;;;;;;;;;;;;;;;
2 | ; FPM Configuration ;
3 | ;;;;;;;;;;;;;;;;;;;;;
4 |
5 | ; All relative paths in this configuration file are relative to PHP's install
6 | ; prefix (/usr/local). This prefix can be dynamically changed by using the
7 | ; '-p' argument from the command line.
8 |
9 | ;;;;;;;;;;;;;;;;;;
10 | ; Global Options ;
11 | ;;;;;;;;;;;;;;;;;;
12 |
13 | [global]
14 | ; Pid file
15 | ; Note: the default prefix is /usr/local/var
16 | ; Default Value: none
17 | ;pid = run/php-fpm.pid
18 |
19 | ; Error log file
20 | ; If it's set to "syslog", log is sent to syslogd instead of being written
21 | ; into a local file.
22 | ; Note: the default prefix is /usr/local/var
23 | ; Default Value: log/php-fpm.log
24 | ;error_log = log/php-fpm.log
25 |
26 | ; syslog_facility is used to specify what type of program is logging the
27 | ; message. This lets syslogd specify that messages from different facilities
28 | ; will be handled differently.
29 | ; See syslog(3) for possible values (ex daemon equiv LOG_DAEMON)
30 | ; Default Value: daemon
31 | ;syslog.facility = daemon
32 |
33 | ; syslog_ident is prepended to every message. If you have multiple FPM
34 | ; instances running on the same server, you can change the default value
35 | ; which must suit common needs.
36 | ; Default Value: php-fpm
37 | ;syslog.ident = php-fpm
38 |
39 | ; Log level
40 | ; Possible Values: alert, error, warning, notice, debug
41 | ; Default Value: notice
42 | ;log_level = notice
43 |
44 | ; Log limit on number of characters in the single line (log entry). If the
45 | ; line is over the limit, it is wrapped on multiple lines. The limit is for
46 | ; all logged characters including message prefix and suffix if present. However
47 | ; the new line character does not count into it as it is present only when
48 | ; logging to a file descriptor. It means the new line character is not present
49 | ; when logging to syslog.
50 | ; Default Value: 1024
51 | ;log_limit = 4096
52 |
53 | ; Log buffering specifies if the log line is buffered which means that the
54 | ; line is written in a single write operation. If the value is false, then the
55 | ; data is written directly into the file descriptor. It is an experimental
56 | ; option that can potentionaly improve logging performance and memory usage
57 | ; for some heavy logging scenarios. This option is ignored if logging to syslog
58 | ; as it has to be always buffered.
59 | ; Default value: yes
60 | ;log_buffering = no
61 |
62 | ; If this number of child processes exit with SIGSEGV or SIGBUS within the time
63 | ; interval set by emergency_restart_interval then FPM will restart. A value
64 | ; of '0' means 'Off'.
65 | ; Default Value: 0
66 | ;emergency_restart_threshold = 0
67 |
68 | ; Interval of time used by emergency_restart_interval to determine when
69 | ; a graceful restart will be initiated. This can be useful to work around
70 | ; accidental corruptions in an accelerator's shared memory.
71 | ; Available Units: s(econds), m(inutes), h(ours), or d(ays)
72 | ; Default Unit: seconds
73 | ; Default Value: 0
74 | ;emergency_restart_interval = 0
75 |
76 | ; Time limit for child processes to wait for a reaction on signals from master.
77 | ; Available units: s(econds), m(inutes), h(ours), or d(ays)
78 | ; Default Unit: seconds
79 | ; Default Value: 0
80 | ;process_control_timeout = 0
81 |
82 | ; The maximum number of processes FPM will fork. This has been designed to control
83 | ; the global number of processes when using dynamic PM within a lot of pools.
84 | ; Use it with caution.
85 | ; Note: A value of 0 indicates no limit
86 | ; Default Value: 0
87 | ; process.max = 128
88 |
89 | ; Specify the nice(2) priority to apply to the master process (only if set)
90 | ; The value can vary from -19 (highest priority) to 20 (lowest priority)
91 | ; Note: - It will only work if the FPM master process is launched as root
92 | ; - The pool process will inherit the master process priority
93 | ; unless specified otherwise
94 | ; Default Value: no set
95 | ; process.priority = -19
96 |
97 | ; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging.
98 | ; Default Value: yes
99 | ;daemonize = yes
100 |
101 | ; Set open file descriptor rlimit for the master process.
102 | ; Default Value: system defined value
103 | ;rlimit_files = 1024
104 |
105 | ; Set max core size rlimit for the master process.
106 | ; Possible Values: 'unlimited' or an integer greater or equal to 0
107 | ; Default Value: system defined value
108 | ;rlimit_core = 0
109 |
110 | ; Specify the event mechanism FPM will use. The following is available:
111 | ; - select (any POSIX os)
112 | ; - poll (any POSIX os)
113 | ; - epoll (linux >= 2.5.44)
114 | ; - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0)
115 | ; - /dev/poll (Solaris >= 7)
116 | ; - port (Solaris >= 10)
117 | ; Default Value: not set (auto detection)
118 | ;events.mechanism = epoll
119 |
120 | ; When FPM is built with systemd integration, specify the interval,
121 | ; in seconds, between health report notification to systemd.
122 | ; Set to 0 to disable.
123 | ; Available Units: s(econds), m(inutes), h(ours)
124 | ; Default Unit: seconds
125 | ; Default value: 10
126 | ;systemd_interval = 10
127 |
128 | ;;;;;;;;;;;;;;;;;;;;
129 | ; Pool Definitions ;
130 | ;;;;;;;;;;;;;;;;;;;;
131 |
132 | ; Multiple pools of child processes may be started with different listening
133 | ; ports and different management options. The name of the pool will be
134 | ; used in logs and stats. There is no limitation on the number of pools which
135 | ; FPM can handle. Your system will tell you anyway :)
136 |
137 | ; Include one or more files. If glob(3) exists, it is used to include a bunch of
138 | ; files from a glob(3) pattern. This directive can be used everywhere in the
139 | ; file.
140 | ; Relative path can also be used. They will be prefixed by:
141 | ; - the global prefix if it's been set (-p argument)
142 | ; - /usr/local otherwise
143 | include=etc/php-fpm.d/*.conf
144 | user=root
145 |
--------------------------------------------------------------------------------
/docker-containers/kodbox/app/setting_user.example:
--------------------------------------------------------------------------------
1 | 'mysqli',
4 | 'DB_HOST' => 'MYSQL_SERVER',
5 | 'DB_PORT' => 'MYSQL_PORT',
6 | 'DB_USER' => 'MYSQL_USER',
7 | 'DB_PWD' => 'MYSQL_PASSWORD',
8 | 'DB_NAME' => 'MYSQL_DATABASE',
9 | 'DB_SQL_LOG' => true,
10 | 'DB_FIELDS_CACHE' => true,
11 | 'DB_SQL_BUILD_CACHE' => false,
12 | );
13 | $config['cache']['sessionType'] = 'SESSION_TYPE';
14 | $config['cache']['cacheType'] = 'SESSION_TYPE';
15 | $config['cache']['SESSION_TYPE']['host'] = 'SESSION_HOST';
16 | $config['cache']['SESSION_TYPE']['port'] = 'SESSION_PORT';
17 |
--------------------------------------------------------------------------------
/docker-containers/kodbox/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.6'
2 |
3 | services:
4 | db:
5 | image: mariadb
6 | command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
7 | restart: always
8 | volumes:
9 | - ./mysql:/var/lib/mysql
10 | - ./app/initdb.d:/docker-entrypoint-initdb.d
11 | environment:
12 | - TZ=Asia/Shanghai
13 | - MYSQL_ALLOW_EMPTY_PASSWORD=yes
14 | - MYSQL_DATABASE_FILE=/run/secrets/mysql_db
15 | - MYSQL_USER_FILE=/run/secrets/mysql_user
16 | - MYSQL_PASSWORD_FILE=/run/secrets/mysql_password
17 | secrets:
18 | - mysql_db
19 | - mysql_password
20 | - mysql_user
21 |
22 | app:
23 | build: ./app
24 | command:
25 | - php-fpm
26 | - -R
27 | volumes:
28 | - ./www:/var/www/html
29 | - /media:/media/pi-media # 可以挂载移动硬盘
30 | - /home/pi:/media/pi-home
31 | - ./app/php-fpm.conf:/usr/local/etc/php-fpm.conf # root运行配置文件
32 | environment:
33 | - MYSQL_SERVER=db
34 | - MYSQL_DATABASE_FILE=/run/secrets/mysql_db
35 | - MYSQL_USER_FILE=/run/secrets/mysql_user
36 | - MYSQL_PASSWORD_FILE=/run/secrets/mysql_password
37 | - SESSION_HOST=redis
38 | #- KODBOX_ADMIN_USER=/run/secrets/kodbox_admin_user
39 | #- KODBOX_ADMIN_PASSWORD=/run/secrets/kodbox_admin_password
40 | restart: always
41 | secrets:
42 | - mysql_db
43 | - mysql_password
44 | - mysql_user
45 | - kodbox_admin_user
46 | - kodbox_admin_password
47 |
48 | redis:
49 | image: redis:alpine
50 | environment:
51 | - TZ=Asia/Shanghai
52 | restart: always
53 | volumes:
54 | - ./redis:/data
55 |
56 | web:
57 | image: nginx:alpine
58 | restart: always
59 | ports:
60 | - 1380:80
61 | - 1443:443
62 | volumes:
63 | #- /data/logs/nginx/kodbox:/var/log/nginx/kodbox
64 | - ./web/sslcerts:/etc/sslcerts:ro
65 | - ./www:/var/www/html/kodbox:ro
66 | - ./web/conf.d:/etc/nginx/conf.d
67 | - ./web/nginx.conf:/etc/nginx/nginx.conf
68 |
69 | secrets:
70 | mysql_db:
71 | file: ./app/mysql_db.txt
72 | mysql_password:
73 | file: ./app/mysql_password.txt
74 | mysql_user:
75 | file: ./app/mysql_user.txt
76 | kodbox_admin_user:
77 | file: ./app/kodbox_admin_user.txt
78 | kodbox_admin_password:
79 | file: ./app/kodbox_admin_password.txt
80 |
81 | volumes:
82 | db:
83 | nextcloud:
84 | html:
85 |
86 |
--------------------------------------------------------------------------------
/docker-containers/kodbox/install.sh:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/docker-containers/kodbox/install.sh
--------------------------------------------------------------------------------
/docker-containers/kodbox/web/conf.d/kodbox.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | server_name nas.o2.ethanzhu.ga;
4 | rewrite ^ https://$server_name$request_uri? permanent; # enforce https
5 | }
6 |
7 | upstream php-kodbox-handler {
8 | server app:9000;
9 | }
10 |
11 | server {
12 | listen 443 ssl;
13 | server_name nas.o2.ethanzhu.ga;
14 |
15 | ssl_certificate /etc/sslcerts/tls.crt;
16 | ssl_certificate_key /etc/sslcerts/tls.key;
17 | # ssl_dhparam
18 |
19 | # support only believed secure ciphersuites using the following priority:
20 |
21 | # SSLv3 is broken by POODLE as of October 2014
22 | ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
23 |
24 | ssl_prefer_server_ciphers on;
25 |
26 | # support only believed secure ciphersuites using the following priority:
27 | # 1.) prefer PFS enabled ciphers
28 | # 2.) prefer AES128 over AES256 for speed (AES128 has completely adequate security for now)
29 | # 3.) Support DES3 for IE8 support
30 | #
31 | # disable the following ciphersuites completely
32 | # 1.) null ciphers
33 | # 2.) ciphers with low security
34 | # 3.) fixed ECDH cipher (does not allow for PFS)
35 | # 4.) known vulnerable cypers (MD5, RC4, etc)
36 | # 5.) little-used ciphers (Camellia, Seed)
37 | ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";
38 |
39 | # Add headers to serve security related headers
40 | # Before enabling Strict-Transport-Security headers please read into this
41 | # topic first.
42 | #add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
43 | #
44 | # WARNING: Only add the preload option once you read about
45 | # the consequences in https://hstspreload.org/. This option
46 | # will add the domain to a hardcoded list that is shipped
47 | # in all major browsers and getting removed from this list
48 | # could take several months.
49 | add_header Referrer-Policy "no-referrer" always;
50 | add_header X-Content-Type-Options "nosniff" always;
51 | add_header X-Download-Options "noopen" always;
52 | add_header X-Frame-Options "SAMEORIGIN" always;
53 | add_header X-Permitted-Cross-Domain-Policies "none" always;
54 | add_header X-Robots-Tag "none" always;
55 | add_header X-XSS-Protection "1; mode=block" always;
56 |
57 | # Remove X-Powered-By, which is an information leak
58 | fastcgi_hide_header X-Powered-By;
59 |
60 | access_log /var/log/nginx/kodbox.evling.me_access.log log_json;
61 | error_log /var/log/nginx/kodbox.evling.me_error.log;
62 |
63 | # Path to the root of your installation
64 | root /var/www/html/kodbox;
65 |
66 | client_max_body_size 10G;
67 | fastcgi_buffers 64 4K;
68 |
69 | # Enable gzip but do not remove ETag headers
70 | gzip on;
71 | gzip_vary on;
72 | gzip_comp_level 4;
73 | gzip_min_length 256;
74 | gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
75 | gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcardtext/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
76 |
77 | # Uncomment if your server is build with the ngx_pagespeed module
78 | # This module is currently not supported.
79 | #pagespeed off;
80 |
81 | location / {
82 | rewrite ^ /index.php;
83 | }
84 |
85 | location ~ ^\/(?:build|tests|config|lib|3rdparty|templates|data)\/ {
86 | deny all;
87 | }
88 | location ~ ^\/(?:\.|autotest|occ|issue|indie|db_|console) {
89 | deny all;
90 | }
91 |
92 | location ~ ^\/(?:index|info|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
93 | fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
94 | set $path_info $fastcgi_path_info;
95 | try_files $fastcgi_script_name =404;
96 | include fastcgi_params;
97 | fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name;
98 | fastcgi_param PATH_INFO $path_info;
99 | # fastcgi_param HTTPS on;
100 |
101 | # Avoid sending the security headers twice
102 | fastcgi_param modHeadersAvailable true;
103 |
104 | # Enable pretty urls
105 | fastcgi_param front_controller_active true;
106 | fastcgi_pass php-kodbox-handler;
107 | fastcgi_intercept_errors on;
108 | fastcgi_request_buffering off;
109 | }
110 |
111 | location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
112 | try_files $uri/ =404;
113 | index index.php;
114 | }
115 |
116 | # Adding the cache control header for js, css and map files
117 | # Make sure it is BELOW the PHP block
118 | location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
119 | try_files $uri /index.php$request_uri;
120 | add_header Cache-Control "public, max-age=15778463";
121 | # Add headers to serve security related headers (It is intended to
122 | # have those duplicated to the ones above)
123 | # Before enabling Strict-Transport-Security headers please read into
124 | # this topic first.
125 | #add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
126 | #
127 | # WARNING: Only add the preload option once you read about
128 | # the consequences in https://hstspreload.org/. This option
129 | # will add the domain to a hardcoded list that is shipped
130 | # in all major browsers and getting removed from this list
131 | # could take several months.
132 | add_header Referrer-Policy "no-referrer" always;
133 | add_header X-Content-Type-Options "nosniff" always;
134 | add_header X-Download-Options "noopen" always;
135 | add_header X-Frame-Options "SAMEORIGIN" always;
136 | add_header X-Permitted-Cross-Domain-Policies "none" always;
137 | add_header X-Robots-Tag "none" always;
138 | add_header X-XSS-Protection "1; mode=block" always;
139 |
140 | # Optional: Don't log access to assets
141 | #access_log off;
142 | }
143 |
144 | location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$ {
145 | try_files $uri /index.php$request_uri;
146 | # Optional: Don't log access to other assets
147 | #access_log off;
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/docker-containers/kodbox/web/nginx.conf:
--------------------------------------------------------------------------------
1 |
2 | user nginx;
3 | worker_processes auto;
4 |
5 | error_log /var/log/nginx/error.log warn;
6 | pid /var/run/nginx.pid;
7 |
8 |
9 | events {
10 | worker_connections 1024;
11 | }
12 |
13 |
14 | http {
15 | include /etc/nginx/mime.types;
16 | default_type application/octet-stream;
17 |
18 | log_format log_json '{ "@timestamp": "$time_iso8601",'
19 | '"@source": "$server_addr",'
20 | '"hostname": "$hostname",'
21 | '"http_x_forwarded_for": "$http_x_forwarded_for", '
22 | '"remote_addr": "$remote_addr", '
23 | '"remote_user": "$remote_user", '
24 | '"request_method": "$request_method",'
25 | '"scheme": "$scheme",'
26 | '"domain": "$server_name",'
27 | '"http_referer": "$http_referer", '
28 | '"request_uri": "$request_uri",'
29 | '"args": "$args",'
30 | '"body_bytes_sent": "$body_bytes_sent", '
31 | '"status": "$status", '
32 | '"http_user_agent": "$http_user_agent", '
33 | '"https": "$https", '
34 | '"time_local": "$time_local", '
35 | '"request_time": "$request_time", '
36 | '"upstream_response_time": "$upstream_response_time",'
37 | '"upstream_addr": "$upstream_addr",'
38 | '"trace_id": "$http_trace_id", '
39 | '"span_id": "$http_span_id" '
40 | '}';
41 |
42 |
43 | access_log /var/log/nginx/access.log log_json;
44 |
45 | sendfile on;
46 | #tcp_nopush on;
47 |
48 | keepalive_timeout 65;
49 |
50 | #gzip on;
51 |
52 | include /etc/nginx/conf.d/*.conf;
53 | proxy_connect_timeout 300;
54 | proxy_send_timeout 300;
55 | proxy_read_timeout 300;
56 | proxy_buffer_size 16k;
57 | proxy_buffers 4 64k;
58 | proxy_busy_buffers_size 128k;
59 | proxy_temp_file_write_size 128k;
60 | }
61 |
--------------------------------------------------------------------------------
/docker-containers/kodbox/web/sslcerts/tls.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIC1TCCAb2gAwIBAgIUINz9z3tf9ra9qQzjCb1fi3xwQyEwDQYJKoZIhvcNAQEL
3 | BQAwDjEMMAoGA1UEAwwDY2EtMB4XDTIwMDcxOTA2MTczNVoXDTMwMDcxNzA2MTcz
4 | NVowADCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALeN2iWly5vj7JZA
5 | OrCWNzWM8WpDGsqQofZn2btCQXGhlIUYrcnNn2zFMAm+3JhICYgzUrOpDSiPknDF
6 | EB/WryUvZOQvI/O+ETh9j505i1vZniLEhPakvSIpS9tvAxaK7M3c/td0bpRkT1me
7 | o7Ipynjt/Gro00elRGq0t8aX2Orfj6UF5nyAKyGvQ158WLFxNgwOcbzFKvaVjzD9
8 | bBW+bGfyuKaoebCptTvrfxl+8DbVuhe3ngs2pb+dVAkCZpuMMd0PG2fhU/cKYf3q
9 | b3cN6Dli6SAPDKXK8TwDGq78+CNPF9bUVcLuzxODAM3TK97f4X3Jq7vQE2PhtslU
10 | ZAralBkCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwHQYDVR0lBBYw
11 | FAYIKwYBBQUHAwIGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4IBAQB+vjCceixh
12 | 8eaOZ/3pY12w4NSbH1A65u5J8gnHhfjh0hVcHSizmUAAgD7xv24Futzl5PM+wgHP
13 | j+opipMizhi/c5YZXJitDtFodTjKO5wECeB050oBv1ASTEZDjmlsnmITRvC8pIux
14 | 5PmjOu4lscs4CfFhcPraNhh1grNIsGyPyPYOXGkrf9TOB5v0ltadK3Ep3sRIy8dH
15 | XDWgKn1TM/gL7W/3BlHPUReDYlRCJNlXH/sRkH2zrq1CN8qAOxfndygj1zeqNm5i
16 | +vKWbBzQ+Tu7G4ov/A1c/TcNLroWW/u8pxZfVeMDpAx47K5+g/IN1z+ZSio0m2Rs
17 | ACe1WwyZi6dz
18 | -----END CERTIFICATE-----
19 |
--------------------------------------------------------------------------------
/docker-containers/kodbox/web/sslcerts/tls.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEowIBAAKCAQEAt43aJaXLm+PslkA6sJY3NYzxakMaypCh9mfZu0JBcaGUhRit
3 | yc2fbMUwCb7cmEgJiDNSs6kNKI+ScMUQH9avJS9k5C8j874ROH2PnTmLW9meIsSE
4 | 9qS9IilL228DForszdz+13RulGRPWZ6jsinKeO38aujTR6VEarS3xpfY6t+PpQXm
5 | fIArIa9DXnxYsXE2DA5xvMUq9pWPMP1sFb5sZ/K4pqh5sKm1O+t/GX7wNtW6F7ee
6 | Czalv51UCQJmm4wx3Q8bZ+FT9wph/epvdw3oOWLpIA8MpcrxPAMarvz4I08X1tRV
7 | wu7PE4MAzdMr3t/hfcmru9ATY+G2yVRkCtqUGQIDAQABAoIBAG/2ryJXx6MHnMDp
8 | 3OLqPjMEDh5rYGQ/ZQwQvNdkytatYRLuwtNeAekvPuYy7gxVpLrX05KTg9tB+Gmh
9 | Svygz6U3C6vEtYFwZsC2lmupNkCItdUvWou4YUX9OrBXPuL5SwknzKtP8kPCDET2
10 | Z5O9uiuZv2bXLkl9ngYYxiD1bvOU8Sc3pVxMYerJj+LfKyeYLAkORF1xYfz9Ahyq
11 | YY27mcbgnYR1iu769GgrBYfoBHNm+RIjGV4savxCkBdAyLXUQL0GQ+y+7fXEoLTW
12 | sLIOs11WKmIQbeOI5j/WticTd3bDOYsqm18WiUHXUk2CyRbPXprHYJW5dRuTGfUk
13 | xPOyJ6ECgYEA7yEFL7Bvp75dy9Sfm/+Don/eZBAocQzWyt2V6KFePSFt4XXTFXWE
14 | MXiS/bzWA3gU6EBGyet92nT7mF7wiOh0cd2aTITgR1zUAsykNK7k6HbBWtGRkAI4
15 | v2oTsbMFUvHj3FcZTT6KrZgraAJagnss3SxuAC/W7UoTY/nQQ1RZInMCgYEAxIET
16 | 2FP37xSN5u/eY5zZ1EufSrexRf0DrZGR12vJhKlGxaMpNXrJ5Hd6BmOxtWTfYDRl
17 | 18DOM32SIYz3EpQeHJ1oMwYHE76e8YyfYwtg9aRYCqRi2OFP1uF6Qh1ByRdtfA9a
18 | 4e33KSn76ySUikg8loQ+PfuXiUBUgzjay/lrMEMCgYEAineHZkb3UJ21+HqFdbJu
19 | SeFbKHwGvvedRNksngka5bD+zIgKk6l5w5+7FfyLvHSDPr1BgFjBhocozOFkzRI1
20 | o12bpGVo7Um+ZmSTTQJdAJMLgYhKjqYKsCQ/hS1RjucMd6FjwEvPx5eOwuph+J5U
21 | qzm39Jm/DaZQNhsI0oP8HSsCgYBGYLRq1igGSKZJ/772jka18h+q8v9awbN/hpNl
22 | RAV4refbAQTRUpjcaq4Ze7s57FbUbe/LxhIT/vVHbuVOkh32wamAHLiMKcljWan8
23 | Hycq0yF1Lkr4wjmGDFttMm1NSEa+GAHEySWsaI0BOqi4ngaVIefo6yLq1U9vb/1s
24 | 8HejYQKBgFUyg8hkuEMogMBmIV5s5F6G4U3ZSE6CeYPs1d30FwsDdtjvibuV1dhw
25 | KxPGSNd+UIXl92SINykepFMAGes3knDdKLjz/PGx9Gy5k/OKgyltwVmSucq7Hafb
26 | g8vPZkg8vgfRlRS1Ele5HL3hyyB+Ql1d4eM4Ykl+IED7JJeAZfNi
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/docker-containers/kode-syncting-webdav/install.sh:
--------------------------------------------------------------------------------
1 | docker run -d \
2 | --name kodexplorer \
3 | --hostname=kodexplorer \
4 | -p 5210:5210 \
5 | -p 5218:5218 \
6 | -p 8384:8384 \
7 | -v /home/pi/koddata:/koddata \
8 | -v /media:/koddata/Group/public/home/media \
9 | -v /home/pi:/koddata/Group/public/home/pi\
10 | --restart unless-stopped \
11 | ethanzhu/kode-syncthing
12 |
13 | docker run -d \
14 | -v $HOME/Download:/data/download \
15 | -v /media:/data/media \
16 | -e USERNAME=webdav \
17 | -e PASSWORD=webdav \
18 | -p 1480:80 \
19 | --restart=unless-stopped \
20 | --name=webdav \
21 | ugeek/webdav:arm-alpine
--------------------------------------------------------------------------------
/everyday_wechat/install.sh:
--------------------------------------------------------------------------------
1 | git clone https://github.com/cloudswave/EverydayWechat
2 | cd EverydayWechat
3 | pip3 install -r requirements.txt
4 | # 或者是使用 pip
5 | # pip install -r requirements.txt
6 | # python run.py
7 | screen python run.py #可以使用screen让程序后台运行
8 |
--------------------------------------------------------------------------------
/frpc/frpc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/frpc/frpc
--------------------------------------------------------------------------------
/frpc/frpc.ini:
--------------------------------------------------------------------------------
1 | [common]
2 | #server_addr = 23.105.212.162
3 | #查看更多服务器 http://www.frps.top/
4 | server_addr = frpzj.kskxs.com
5 | server_port = 8000
6 | privilege_token = yxhpib
7 | token = yxhpib
8 | [pi-ssh]
9 | type = tcp
10 | local_ip = 127.0.0.1
11 | local_port = 22
12 | #remote_port = 8023
13 | remote_port = 56675
14 | [pi-samba]
15 | type = tcp
16 | local_ip = 127.0.0.1
17 | local_port = 139
18 | remote_port = 56139
19 |
20 | [pi-php]
21 | type = http
22 | local_ip = 127.0.0.1
23 | local_port = 80
24 | remote_port = 8081
25 | custom_domains = ethanzhu.frpzj.kskxs.com
26 |
27 | [pi-php2]
28 | type = http
29 | local_ip = 127.0.0.1
30 | local_port = 80
31 | remote_port = 8081
32 | custom_domains = nas.zhuxiaobo.ml
33 |
34 | [pi-hass]
35 | type = http
36 | local_ip = 127.0.0.1
37 | local_port = 8123
38 | remote_port = 8081
39 | ###locations = /bt
40 | #custom_domains = 23.105.212.162
41 | #subdomain = ethanzhu
42 | custom_domains = ethan-hass.frpzj.kskxs.com
43 |
44 | [pi-hass2]
45 | type = http
46 | local_ip = 127.0.0.1
47 | local_port = 8123
48 | remote_port = 8081
49 | custom_domains = home.zhuxiaobo.ml
50 |
51 | [pi-node]
52 | type = http
53 | local_ip = 127.0.0.1
54 | local_port = 3000
55 | remote_port = 8081
56 | custom_domains = ethan-node.frpzj.kskxs.com
57 |
58 | [pi-aria2]
59 | type = http
60 | local_ip = 127.0.0.1
61 | local_port = 6800
62 | remote_port = 8081
63 | custom_domains = pi-aria2.frpzj.kskxs.com
64 |
65 | [pi-aria]
66 | type = http
67 | local_ip = 127.0.0.1
68 | local_port = 6800
69 | remote_port = 8081
70 | custom_domains = aria.zhuxiaobo.ml
71 |
72 | [pi-syncthing]
73 | type = http
74 | local_ip = 127.0.0.1
75 | local_port = 8384
76 | remote_port = 8081
77 | custom_domains = sync.zhuxiaobo.ml
78 |
79 | [pi-qbittorrent]
80 | type = http
81 | local_ip = 127.0.0.1
82 | local_port = 8081
83 | remote_port = 8081
84 | custom_domains = qb.zhuxiaobo.ml
85 |
86 | [pi-webssh]
87 | type = http
88 | local_ip = 127.0.0.1
89 | local_port = 8888
90 | remote_port = 8081
91 | custom_domains = webssh.zhuxiaobo.ml
92 |
--------------------------------------------------------------------------------
/frpc/frpc_180704.ini:
--------------------------------------------------------------------------------
1 | [common]
2 | server_addr = frp3.chuantou.org
3 | server_port = 7000
4 | token = www.chuantou.org
5 | protocol = kcp
6 | # 标注你的代理名字,随便选择一个跟别人不一样即可
7 | user = ethanzhu
8 | [pi-ssh]
9 | type = tcp
10 | local_ip = 127.0.0.1
11 | local_port = 22
12 | remote_port = 56675
13 |
14 |
15 | [pi-php]
16 | type = http
17 | local_ip = 127.0.0.1
18 | local_port = 80
19 | subdomain = ethanzhu
20 |
21 | [pi-node]
22 | type = http
23 | local_ip = 127.0.0.1
24 | local_port = 3000
25 | subdomain = ethan-node
26 |
27 | #[pi-aria2]
28 | type = http
29 | local_ip = 127.0.0.1
30 | local_port = 6800
31 | subdomain = pi-aria2
32 |
33 | [pi-hass]
34 | type = http
35 | local_ip = 127.0.0.1
36 | local_port = 8123
37 | remote_port = 56678
38 | #custom_domains = ethan-hass.frp3.chuantou.org
39 | subdomain = ethan-hass
40 |
41 | [pi-hass2]
42 | type = tcp
43 | local_port = 8123
44 | remote_port = 56678
45 |
46 |
47 | [pi-shellinabox]
48 | type = http
49 | local_ip = 127.0.0.1
50 | local_port = 4200
51 | subdomain = ethan-shell
52 |
--------------------------------------------------------------------------------
/frpc/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | mkdir /home/pi/bin/
3 | #cp -r * /home/pi/bin/
4 | basepath=$(cd `dirname $0`; pwd)
5 | ln -s $basepath/frpc ~/bin/frpc
6 | ln -s $basepath/monitor.sh ~/bin/monitor.sh
7 | ln -s $basepath/frpc.ini ~/bin/frpc.ini
8 |
9 | nohup ~/bin/monitor.sh >> /dev/null &
10 |
--------------------------------------------------------------------------------
/frpc/monitor.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | LOG_FILE="/home/pi/boot.log"
3 | logit(){
4 | echo $(date "+%Y-%m-%d %H:%M:%S"): ${*} >> ${LOG_FILE}
5 | }
6 | while true;do
7 | count=`ps -ef|grep frpc|grep -v grep`
8 | if [ "$?" != "0" ];then
9 | logit "no frpc, run frpc"
10 | /home/pi/bin/frpc -c /home/pi/bin/frpc.ini
11 | #else
12 | #logit "frpc is runing..."
13 | fi
14 | sleep 5
15 | done
16 |
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/automations.yaml:
--------------------------------------------------------------------------------
1 | - alias: weather_report
2 | initial_state: true
3 | trigger:
4 | - platform: time
5 | hours: 8
6 | minutes: 20
7 | seconds: 0
8 |
9 | condition:
10 | condition: numeric_state
11 | entity_id: sensor.weather_temperature
12 | above: 0 #判断气温是否高于34°C
13 |
14 | action:
15 | - service: tts.baidu_say
16 | data_template:
17 | entity_id: media_player.vlc
18 | message: "现在播报天气信息。温度,{{states('sensor.weather_temperature')}}°C, 湿度{{states('sensor.weather_humidity')}},风速{{states('sensor.weather_wind_speed')}}, 气压{{states('sensor.weather_pressure')}}"
19 |
20 | - alias: notify publish
21 | #trigger:
22 | #at: '8:00'
23 | #platform: time
24 | trigger:
25 | platform: homeassistant
26 | # Event can also be 'shutdown'
27 | event: start
28 | action:
29 | service: notify.my_notify
30 | data:
31 | title: 提示
32 | message: '智能家居系统已经启动'
33 | target: g-8d131ed3-fdef-4d4b-854e-9a26f02b
34 |
35 | # 播放
36 | - alias: musicbox_play
37 | trigger:
38 | platform: time
39 | hours: 8
40 | minutes: 30
41 | seconds: 0
42 |
43 | action:
44 | service: shell_command.musicbox_play
45 |
46 | - alias: musicbox_stop
47 | trigger:
48 | platform: time
49 | hours: 10
50 | minutes: 30
51 | seconds: 0
52 |
53 | action:
54 | service: shell_command.musicbox_kill
55 |
56 | # 定时关机
57 | - alias: pi_shutdown
58 | trigger:
59 | platform: time
60 | hours: 11
61 | minutes: 30
62 | seconds: 0
63 |
64 | action:
65 | service: shell_command.pi_shutdown
66 |
67 | - alias: lifesuggest
68 | trigger:
69 | - event: sunrise
70 | platform: sun
71 |
72 | condition: []
73 | action:
74 | data_template:
75 | message: >
76 | 今天{{ states.sensor.suggestion_trav.state}}外出旅行,{{ states.sensor.suggestion_trav.attributes["建议"] }},祝您旅途愉快
77 | service: tts.baidu_say
78 |
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/configuration.yaml:
--------------------------------------------------------------------------------
1 | homeassistant:
2 | # Name of the location where Home Assistant is running
3 | name: 朱小波的家
4 | # Location required to calculate the time the sun rises and sets
5 | latitude: 31.0456
6 | longitude: 121.3997
7 | # Impacts weather/sunrise data (altitude above sea level in meters)
8 | elevation: 0
9 | # metric for Metric, imperial for Imperial
10 | unit_system: metric
11 | # Pick yours from here: http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
12 | time_zone: Asia/Shanghai
13 | # Customization file
14 | customize: !include customize.yaml
15 | packages: !include_dir_named packages
16 |
17 | # Show links to resources in log and frontend
18 | introduction:
19 |
20 | # Enables the frontend
21 | frontend:
22 | extra_html_url:
23 | - /local/custom_ui/state-card-custom-ui.html
24 | #- /local/custom_ui/state-card-diy.html
25 | extra_html_url_es5:
26 | - /local/custom_ui/state-card-custom-ui-es5.html
27 | #- /local/custom_ui/state-card-diy.html
28 | # Enables configuration UI
29 | config:
30 |
31 | http:
32 | # Secrets are defined in the file secrets.yaml
33 | api_password: 123456
34 | # Uncomment this if you are using SSL/TLS, running in Docker container, etc.
35 | # base_url: example.duckdns.org:8123
36 |
37 | # Checks for available updates
38 | # Note: This component will send some information about your system to
39 | # the developers to assist with development of Home Assistant.
40 | # For more information, please see:
41 | # https://home-assistant.io/blog/2016/10/25/explaining-the-updater/
42 | updater:
43 | # Optional, allows Home Assistant developers to focus on popular components.
44 | # include_used_components: true
45 |
46 | # Discover some devices automatically
47 | discovery:
48 |
49 | # Allows you to issue voice commands from the frontend in enabled browsers
50 | conversation:
51 |
52 | # Enables support for tracking state changes over time
53 | history:
54 |
55 | # View all events in a logbook
56 | logbook:
57 |
58 | # Enables a map showing the location of tracked devices
59 | map:
60 |
61 | # Track the sun
62 | sun:
63 |
64 | # Weather prediction
65 | sensor:
66 | - platform: yr
67 | name: weather
68 | forecast: 24 #未来24小时天气,可有手工按需修改
69 | monitored_conditions:
70 | - temperature #气温
71 | - precipitation #雨量
72 | - windSpeed #风速
73 | - pressure #气压
74 | - windDirection #风向
75 | - humidity #湿度
76 |
77 | # Text to speech
78 | tts:
79 | - platform: baidu
80 | #app_id,api_key,secret_key从百度云上注册得到
81 | app_id: 11337674
82 | api_key: XtR74Qq3EvCRQNiLT7fHGna1
83 | secret_key: XMeYTwjGOI4k6hC8PkTqM9nRew3Ehszt
84 | #speed:语速0-9(缺省5)pitch:语调0-9(缺省5)
85 | volume: 15 #音量0-15(缺省5)
86 | #person:声音(0:女,1:男,3:百度合成,4:百度合成,缺省0)
87 | speed: 5
88 | pitch: 5
89 | person: 0
90 |
91 | media_player :
92 | - platform: vlc
93 | name: vlc
94 |
95 | # Cloud
96 | cloud:
97 |
98 | switch:
99 | platform: wake_on_lan
100 | friendly_name: 电脑电源
101 | mac_address: "00-E0-70-6B-40-33"
102 | host: "192.168.1.142"
103 | turn_off:
104 | service: shell_command.turn_off_pc
105 |
106 | notify:
107 | - name: my_notify
108 | platform: alert_over
109 | from_source: s-003b4305-8753-4290-9b56-3ec11cc7
110 |
111 | shell_command:
112 | musicbox_play: killall shairport ; su - pi -c 'tmux new-session -d -s musicbox musicbox -c "?"'
113 | musicbox_kill: /home/pi/shairport/shairport -a pi -d ; su - pi -c 'tmux kill-session -t musicbox'
114 | pi_shutdown: halt
115 | turn_off_pc: 'curl -X GET http://192.168.1.142:8000/?action=System.Shutdown'
116 |
117 | group : !include groups.yaml
118 | automation: !include automations.yaml
119 | script : !include scripts.yaml
120 |
121 | logger:
122 | default: info
123 | logs:
124 | homeassistant.components.shell_command: info
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/custom_components/media_player/vlc.py:
--------------------------------------------------------------------------------
1 | """
2 | Provide functionality to interact with vlc devices on the network.
3 |
4 | For more details about this platform, please refer to the documentation at
5 | https://home-assistant.io/components/media_player.vlc/
6 | """
7 | import logging
8 |
9 | import voluptuous as vol
10 |
11 | from homeassistant.components.media_player import (
12 | SUPPORT_PAUSE, SUPPORT_PLAY_MEDIA, SUPPORT_STOP, SUPPORT_VOLUME_MUTE,
13 | SUPPORT_VOLUME_SET, SUPPORT_PLAY, MediaPlayerDevice, PLATFORM_SCHEMA,
14 | MEDIA_TYPE_MUSIC)
15 |
16 | from homeassistant.const import (CONF_NAME, STATE_IDLE, STATE_PAUSED,
17 | STATE_PLAYING)
18 | import homeassistant.helpers.config_validation as cv
19 | import homeassistant.util.dt as dt_util
20 |
21 | REQUIREMENTS = ['python-vlc==1.1.2']
22 |
23 | _LOGGER = logging.getLogger(__name__)
24 |
25 | CONF_ARGUMENTS = 'arguments'
26 | DEFAULT_NAME = 'Vlc'
27 |
28 | SUPPORT_VLC = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \
29 | SUPPORT_PLAY_MEDIA | SUPPORT_PLAY | SUPPORT_STOP
30 |
31 | PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
32 | vol.Optional(CONF_NAME): cv.string,
33 | vol.Optional(CONF_ARGUMENTS, default=''): cv.string,
34 | })
35 |
36 |
37 | # pylint: disable=unused-argument
38 | def setup_platform(hass, config, add_devices, discovery_info=None):
39 | """Set up the vlc platform."""
40 | add_devices([VlcDevice(config.get(CONF_NAME, DEFAULT_NAME),
41 | config.get(CONF_ARGUMENTS))])
42 |
43 |
44 | class VlcDevice(MediaPlayerDevice):
45 | """Representation of a vlc player."""
46 |
47 | def __init__(self, name, arguments):
48 | """Initialize the vlc device."""
49 | import vlc
50 | self._instance = vlc.Instance(arguments)
51 | self._vlc = self._instance.media_player_new()
52 | self._name = name
53 | self._volume = None
54 | self._muted = None
55 | self._state = None
56 | self._media_position_updated_at = None
57 | self._media_position = None
58 | self._media_duration = None
59 |
60 | def update(self):
61 | """Get the latest details from the device."""
62 | import vlc
63 | status = self._vlc.get_state()
64 | if status == vlc.State.Playing:
65 | self._state = STATE_PLAYING
66 | elif status == vlc.State.Paused:
67 | self._state = STATE_PAUSED
68 | else:
69 | self._state = STATE_IDLE
70 | self._media_duration = self._vlc.get_length()/1000
71 | position = self._vlc.get_position() * self._media_duration
72 | if position != self._media_position:
73 | self._media_position_updated_at = dt_util.utcnow()
74 | self._media_position = position
75 |
76 | self._volume = self._vlc.audio_get_volume() / 100
77 | self._muted = (self._vlc.audio_get_mute() == 1)
78 |
79 | return True
80 |
81 | @property
82 | def name(self):
83 | """Return the name of the device."""
84 | return self._name
85 |
86 | @property
87 | def state(self):
88 | """Return the state of the device."""
89 | return self._state
90 |
91 | @property
92 | def volume_level(self):
93 | """Volume level of the media player (0..1)."""
94 | return self._volume
95 |
96 | @property
97 | def is_volume_muted(self):
98 | """Boolean if volume is currently muted."""
99 | return self._muted
100 |
101 | @property
102 | def supported_features(self):
103 | """Flag media player features that are supported."""
104 | return SUPPORT_VLC
105 |
106 | @property
107 | def media_content_type(self):
108 | """Content type of current playing media."""
109 | return MEDIA_TYPE_MUSIC
110 |
111 | @property
112 | def media_duration(self):
113 | """Duration of current playing media in seconds."""
114 | return self._media_duration
115 |
116 | @property
117 | def media_position(self):
118 | """Position of current playing media in seconds."""
119 | return self._media_position
120 |
121 | @property
122 | def media_position_updated_at(self):
123 | """When was the position of the current playing media valid."""
124 | return self._media_position_updated_at
125 |
126 | def media_seek(self, position):
127 | """Seek the media to a specific location."""
128 | track_length = self._vlc.get_length()/1000
129 | self._vlc.set_position(position/track_length)
130 |
131 | def mute_volume(self, mute):
132 | """Mute the volume."""
133 | self._vlc.audio_set_mute(mute)
134 | self._muted = mute
135 |
136 | def set_volume_level(self, volume):
137 | """Set volume level, range 0..1."""
138 | self._vlc.audio_set_volume(int(volume * 100))
139 | self._volume = volume
140 |
141 | def media_play(self):
142 | """Send play command."""
143 | self._vlc.play()
144 | self._state = STATE_PLAYING
145 |
146 | def media_pause(self):
147 | """Send pause command."""
148 | self._vlc.pause()
149 | self._state = STATE_PAUSED
150 |
151 | def media_stop(self):
152 | """Send stop command."""
153 | self._vlc.stop()
154 | self._state = STATE_IDLE
155 |
156 | def play_media(self, media_type, media_id, **kwargs):
157 | """Play media from a URL or file."""
158 | if not media_type == MEDIA_TYPE_MUSIC:
159 | _LOGGER.error(
160 | "Invalid media type %s. Only %s is supported",
161 | media_type, MEDIA_TYPE_MUSIC)
162 | return
163 | self._vlc.set_media(self._instance.media_new(media_id))
164 | self._vlc.play()
165 | self._state = STATE_PLAYING
166 |
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/custom_components/notify/.alert_over.py.swx:
--------------------------------------------------------------------------------
1 | panel_custom:
2 | - name: cloudmusic
3 | sidebar_title: 云音乐
4 | sidebar_icon: mdi:music
5 | url_path: music
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/custom_components/notify/alert_over.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import logging
3 |
4 | import voluptuous as vol
5 |
6 | from homeassistant.components.notify import (ATTR_TARGET, ATTR_TITLE, PLATFORM_SCHEMA, BaseNotificationService)
7 | import homeassistant.helpers.config_validation as cv
8 |
9 | _LOGGER = logging.getLogger(__name__)
10 | CONF_FROM_SOURCE = "from_source"
11 |
12 |
13 | PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
14 | vol.Required(CONF_FROM_SOURCE): cv.string,
15 | })
16 |
17 |
18 |
19 | def get_service(hass, config, discovery_info=None):
20 | return AlertOverNotificationService(config[CONF_FROM_SOURCE])
21 |
22 |
23 | class AlertOverNotificationService(BaseNotificationService):
24 | def __init__(self, from_source):
25 | self.from_source = from_source
26 |
27 | def send_message(self, message="", **kwargs):
28 | receivers = kwargs.get(ATTR_TARGET)
29 | title = kwargs.get(ATTR_TITLE)
30 | try:
31 | for receiver in receivers:
32 | _LOGGER.info("已发送")
33 |
34 | data = {
35 | "source": self.from_source,
36 | "receiver": receiver,
37 | "content": message,
38 | "title": title
39 | }
40 | _LOGGER.info(data)
41 | requests.post(
42 | "https://api.alertover.com/v1/alert",
43 | data=data
44 | )
45 |
46 | except ConnectionError:
47 | _LOGGER.error("连接失败")
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/custom_components/sensor/PhicommTokenGetter.py:
--------------------------------------------------------------------------------
1 | """
2 | Support for Phicomm Token Getter plant sensor.
3 | Developer by NETYJ
4 | version 1.0
5 | """
6 | import logging
7 | import datetime
8 | import requests,json
9 | import voluptuous as vol
10 | import hashlib
11 |
12 | from homeassistant.components.sensor import PLATFORM_SCHEMA
13 | from homeassistant.const import (CONF_NAME,)
14 | from homeassistant.helpers.entity import Entity
15 | import homeassistant.helpers.config_validation as cv
16 |
17 |
18 | _LOGGER = logging.getLogger(__name__)
19 | _INTERVAL = 30
20 |
21 | SCAN_INTERVAL = datetime.timedelta(seconds=_INTERVAL)
22 | DEFAULT_NAME = 'Phicomm Token Getter'
23 | DEFAULT_PATH = '/config/phicomm_token.txt'
24 | CONF_ACCOUNT = 'phicommAccount'
25 | CONF_PWD = 'phicommPassowrd'
26 | CONF_PATH = 'tokenPath'
27 |
28 | ATTR_TOKEN = 'token'
29 |
30 |
31 | PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
32 | vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
33 | vol.Optional(CONF_PATH, default=DEFAULT_PATH): cv.string,
34 | vol.Required(CONF_ACCOUNT): cv.string,
35 | vol.Required(CONF_PWD): cv.string,
36 | })
37 |
38 |
39 | def setup_platform(hass, config, add_devices, discovery_info=None):
40 | """Set up the Phicomm Token sensor."""
41 |
42 | name = config.get(CONF_NAME)
43 | phicommAccount = config.get(CONF_ACCOUNT)
44 | phicommPassowrd = config.get(CONF_PWD)
45 | tokenPath = config.get(CONF_PATH)
46 |
47 | devs = []
48 |
49 | devs.append(PhicommTokenSensor(
50 | hass, name, phicommAccount, phicommPassowrd,tokenPath))
51 |
52 | add_devices(devs)
53 |
54 |
55 | class PhicommTokenSensor(Entity):
56 | """Implementing the Phicomm Token Getter."""
57 | def __init__(self, hass, name,phicommAccount,phicommPassowrd,tokenPath):
58 | """Initialize the sensor."""
59 | #_LOGGER.warning("name:%s, account:%s, pass:%s",name, phicommAccount,phicommPassowrd)
60 |
61 | self._hass = hass
62 | self._name = name
63 | self._phicommAccount = phicommAccount
64 | self._phicommPassowrd = phicommPassowrd
65 | self._tokenPath = tokenPath
66 | self._state = None
67 | self.data = []
68 | self.fIsLogon = False
69 | self.retryCountDown = 0
70 | self.slowDownStep = 0
71 | self.access_token = None
72 | self.lastResponeMsg = ''
73 | self._state_attrs = {
74 | ATTR_TOKEN: None,
75 | }
76 | #self.update()
77 |
78 | @property
79 | def name(self):
80 | """Return the name of the sensor."""
81 | return self._name
82 |
83 | @property
84 | def state(self):
85 | """Return the state of the sensor."""
86 | return self.fIsLogon
87 |
88 | @property
89 | def state_attributes(self):
90 | """Return the state of the sensor."""
91 | return self._state_attrs
92 |
93 | def update(self):
94 | """
95 | Update current conditions.
96 | """
97 | if self._hass.states.is_state('input_boolean.phicomm_token_reset','on'):
98 | states_attrs = {
99 | 'friendly_name':'重试',
100 | 'icon':'mdi:lock-reset'
101 | }
102 | self._hass.states.set('input_boolean.phicomm_token_reset', 'off',states_attrs)
103 | self.slowDownStep = 0
104 | self.retryCountDown = 0
105 | _LOGGER.warning('reset login prcess!')
106 |
107 | if self.fIsLogon:
108 |
109 | headers = {'User-Agent': 'zhilian/5.7.0 (iPhone; iOS 10.0.2; Scale/3.00)',
110 | 'Authorization': self.access_token }
111 | control_resp = requests.get('https://accountsym.phicomm.com/v1/accountDetail', headers=headers,timeout=10)
112 | if control_resp.status_code == 200:
113 | control_obj = control_resp.json()
114 | if int(control_obj['error']) != 0:
115 | self.fIsLogon = False
116 | _LOGGER.warning('Phicomm sync account. Going to renew token!: %s', control_obj)
117 | else:
118 | self.fIsLogon = False
119 | _LOGGER.warning('Phicomm sync account. connecting error! Going to renew token!: %d', control_resp.status_code)
120 |
121 | elif self.retryCountDown <= 0:
122 | if self.slowDownStep < 5:
123 | self.slowDownStep += 1
124 | md5 = hashlib.md5()
125 | md5.update(str(self._phicommPassowrd).encode("utf8"))
126 | payload = {'authorizationcode' : 'feixun.SH_1',
127 | 'password' : md5.hexdigest().upper(),
128 | 'phonenumber' : self._phicommAccount}
129 | #_LOGGER.warning("payload:%s",payload)
130 | headers = {'User-Agent': 'zhilian/5.7.0 (iPhone; iOS 10.0.2; Scale/3.00)'}
131 | resp = requests.post('https://accountsym.phicomm.com/v1/login', headers=headers,params=payload,timeout=10)
132 | if resp.status_code == 200:
133 | obj = resp.json()
134 | error = obj['error']
135 | if int(error) == 0:
136 | self.access_token = obj['access_token']
137 | with open(self._tokenPath, 'w') as f:
138 | f.write(self.access_token)
139 | self._state_attrs = {
140 | ATTR_TOKEN: 'please check'+self._tokenPath+'to review the token.',
141 | }
142 | _LOGGER.warning("access_token:%s",self.access_token)
143 | self.fIsLogon = True
144 | self.retryCountDown = 60
145 | self.slowDownStep = 0
146 | self.lastResponeMsg = ''
147 | elif int(error) == 8:
148 | _LOGGER.error('account login error: ' + obj['error'] + obj['message'])
149 | self.lastResponeMsg = obj['message']
150 | self.slowDownStep += 100
151 | states_attrs = {
152 | 'friendly_name':'重试. Last error: '+ self.lastResponeMsg,
153 | 'icon':'mdi:lock-reset'
154 | }
155 | self._hass.states.set('input_boolean.phicomm_m1_reset', 'off',states_attrs)
156 | else:
157 | self.lastResponeMsg = obj['message']
158 | _LOGGER.error('account login error: ' + obj['error'] + obj['message'])
159 | else:
160 | states_attrs = {'friendly_name':'重试. Last error: '+ self.lastResponeMsg,
161 | 'icon':'mdi:lock-reset'
162 | }
163 | self._hass.states.set('input_boolean.phicomm_m1_reset', 'off',states_attrs)
164 | else:
165 | self.retryCountDown -= _INTERVAL
166 | #_LOGGER.error("retryCountDown:%d", self.retryCountDown)
167 | states_attrs = {
168 | 'friendly_name':'重试. Last error: Logged on at other place!',
169 | 'icon':'mdi:lock-reset'
170 | }
171 | self._hass.states.set('input_boolean.phicomm_token_reset', 'off',states_attrs)
172 |
173 |
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/custom_components/sensor/heweather.py:
--------------------------------------------------------------------------------
1 | import logging
2 | from datetime import timedelta
3 |
4 | # 此处引入了几个异步处理的库
5 | import asyncio
6 | import async_timeout
7 | import aiohttp
8 |
9 | import voluptuous as vol
10 |
11 | # aiohttp_client将aiohttp的session与hass关联起来
12 | # track_time_interval需要使用对应的异步的版本
13 | from homeassistant.helpers.aiohttp_client import async_get_clientsession
14 | from homeassistant.helpers.event import async_track_time_interval
15 |
16 | from homeassistant.components.sensor import PLATFORM_SCHEMA
17 | from homeassistant.const import (
18 | ATTR_ATTRIBUTION, ATTR_FRIENDLY_NAME, TEMP_CELSIUS)
19 | from homeassistant.helpers.entity import Entity
20 | import homeassistant.helpers.config_validation as cv
21 | import homeassistant.util.dt as dt_util
22 |
23 |
24 | _LOGGER = logging.getLogger(__name__)
25 |
26 | TIME_BETWEEN_UPDATES = timedelta(seconds=600)
27 |
28 | CONF_OPTIONS = "options"
29 | CONF_CITY = "city"
30 | CONF_APPKEY = "appkey"
31 |
32 | # 定义三个可选项:温度、湿度、PM2.5
33 | OPTIONS = {
34 | "temprature": [
35 | "Heweather_temperature", "室外温度", "mdi:thermometer", TEMP_CELSIUS],
36 | "humidity": ["Heweather_humidity", "室外湿度", "mdi:water-percent", "%"],
37 | "pm25": ["Heweather_pm25", "PM2.5", "mdi:walk", "μg/m3"],
38 | "no2": ["Heweather_no2", "二氧化氮", "mdi:emoticon-dead", "μg/m3"],
39 | "so2": ["Heweather_so2", "二氧化硫", "mdi:emoticon-dead", "μg/m3"],
40 | "co": ["Heweather_co", "一氧化碳", "mdi:emoticon-dead", "μg/m3"],
41 | "o3": ["Heweather_o3", "臭氧", "mdi:weather-cloudy", "μg/m3"],
42 | "qlty": ["Heweather_qlty", "综合空气质量", "mdi:quality-high", " "],
43 |
44 | }
45 |
46 | ATTR_UPDATE_TIME = "更新时间"
47 | ATTRIBUTION = "来自和风天气的天气数据"
48 |
49 |
50 | PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
51 | vol.Required(CONF_CITY): cv.string,
52 | vol.Required(CONF_APPKEY): cv.string,
53 | vol.Required(CONF_OPTIONS,
54 | default=[]): vol.All(cv.ensure_list, [vol.In(OPTIONS)]),
55 | })
56 |
57 |
58 | @asyncio.coroutine
59 | def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
60 | """这个协程是程序的入口,其中add_devices函数也变成了异步版本."""
61 | _LOGGER.info("setup platform sensor.Heweather...")
62 |
63 | city = config.get(CONF_CITY)
64 | appkey = config.get(CONF_APPKEY)
65 | # 这里通过 data 实例化class weatherdata,并传入调用API所需信息
66 | data = WeatherData(hass, city, appkey)
67 | # 调用data实例中的异步更新函数,yield 现在我简单的理解为将后面函数变成一个生成器,减小内存占用?
68 | yield from data.async_update(dt_util.now())
69 | async_track_time_interval(hass, data.async_update, TIME_BETWEEN_UPDATES)
70 |
71 | # 根据配置文件options中的内容,添加若干个设备
72 | dev = []
73 | for option in config[CONF_OPTIONS]:
74 | dev.append(HeweatherWeatherSensor(data, option))
75 | async_add_devices(dev, True)
76 |
77 |
78 | class HeweatherWeatherSensor(Entity):
79 | """定义一个温度传感器的类,继承自HomeAssistant的Entity类."""
80 |
81 | def __init__(self, data, option):
82 | """初始化."""
83 | self._data = data
84 | self._object_id = OPTIONS[option][0]
85 | self._friendly_name = OPTIONS[option][1]
86 | self._icon = OPTIONS[option][2]
87 | self._unit_of_measurement = OPTIONS[option][3]
88 |
89 | self._type = option
90 | self._state = None
91 | self._updatetime = None
92 |
93 | @property
94 | def name(self):
95 | """返回实体的名字."""
96 | return self._object_id
97 |
98 | @property
99 | def registry_name(self):
100 | """返回实体的friendly_name属性."""
101 | return self._friendly_name
102 |
103 | @property
104 | def state(self):
105 | """返回当前的状态."""
106 | return self._state
107 |
108 | @property
109 | def icon(self):
110 | """返回icon属性."""
111 | return self._icon
112 |
113 | @property
114 | def unit_of_measurement(self):
115 | """返回unit_of_measuremeng属性."""
116 | return self._unit_of_measurement
117 |
118 | @property
119 | def device_state_attributes(self):
120 | """设置其它一些属性值."""
121 | if self._state is not None:
122 | return {
123 | ATTR_ATTRIBUTION: ATTRIBUTION,
124 | ATTR_UPDATE_TIME: self._updatetime
125 | }
126 |
127 | @asyncio.coroutine
128 | def async_update(self):
129 | """update函数变成了async_update."""
130 | self._updatetime = self._data.updatetime
131 |
132 | if self._type == "temprature":
133 | self._state = self._data.temprature
134 | elif self._type == "humidity":
135 | self._state = self._data.humidity
136 | elif self._type == "pm25":
137 | self._state = self._data.pm25
138 | elif self._type == "no2":
139 | self._state = self._data.no2
140 | elif self._type == "so2":
141 | self._state = self._data.so2
142 | elif self._type == "co":
143 | self._state = self._data.co
144 | elif self._type == "o3":
145 | self._state = self._data.o3
146 | elif self._type == "qlty":
147 | self._state = self._data.qlty
148 |
149 |
150 | class WeatherData(object):
151 | """天气相关的数据,存储在这个类中."""
152 |
153 | def __init__(self, hass, city, appkey):
154 | """初始化函数."""
155 | self._hass = hass
156 |
157 | self._url = "https://way.jd.com/he/freeweather"
158 | self._params = {"city": city,
159 | "appkey": appkey}
160 | self._temprature = None
161 | self._humidity = None
162 | self._pm25 = None
163 | self._no2 = None
164 | self._so2 = None
165 | self._co = None
166 | self._o3 = None
167 | self._qlty = None
168 | self._updatetime = None
169 |
170 | @property
171 | def temprature(self):
172 | """温度."""
173 | return self._temprature
174 |
175 | @property
176 | def humidity(self):
177 | """湿度."""
178 | return self._humidity
179 |
180 | @property
181 | def pm25(self):
182 | """pm2.5."""
183 | return self._pm25
184 |
185 | @property
186 | def no2(self):
187 | """no2."""
188 | return self._no2
189 |
190 | @property
191 | def so2(self):
192 | """so2."""
193 | return self._so2
194 |
195 | @property
196 | def co(self):
197 | """co."""
198 | return self._co
199 |
200 | @property
201 | def o3(self):
202 | """o3."""
203 | return self._o3
204 |
205 | @property
206 | def qlty(self):
207 | """o3."""
208 | return self._qlty
209 |
210 | @property
211 | def updatetime(self):
212 | """更新时间."""
213 | return self._updatetime
214 |
215 | @asyncio.coroutine
216 | def async_update(self, now):
217 | """从远程更新信息."""
218 | _LOGGER.info("Update from JingdongWangxiang's OpenAPI...")
219 |
220 | """
221 | # 异步模式的测试代码
222 | import time
223 | _LOGGER.info("before time.sleep")
224 | time.sleep(40)
225 | _LOGGER.info("after time.sleep and before asyncio.sleep")
226 | asyncio.sleep(40)
227 | _LOGGER.info("after asyncio.sleep and before yield from asyncio.sleep")
228 | yield from asyncio.sleep(40)
229 | _LOGGER.info("after yield from asyncio.sleep")
230 | """
231 |
232 | # 通过HTTP访问,获取需要的信息
233 | # 此处使用了基于aiohttp库的async_get_clientsession
234 | try:
235 | session = async_get_clientsession(self._hass)
236 | with async_timeout.timeout(15, loop=self._hass.loop):
237 | response = yield from session.post(
238 | self._url, data=self._params)
239 |
240 | except(asyncio.TimeoutError, aiohttp.ClientError):
241 | _LOGGER.error("Error while accessing: %s", self._url)
242 | return
243 |
244 | if response.status != 200:
245 | _LOGGER.error("Error while accessing: %s, status=%d",
246 | self._url,
247 | response.status)
248 | return
249 |
250 | result = yield from response.json()
251 |
252 | if result is None:
253 | _LOGGER.error("Request api Error")
254 | return
255 | elif result["code"] != "10000":
256 | _LOGGER.error("Error API return, code=%s, msg=%s",
257 | result["code"],
258 | result["msg"])
259 | return
260 |
261 | # 根据http返回的结果,更新数据
262 | all_result = result["result"]["HeWeather5"][0]
263 | self._temprature = all_result["now"]["tmp"]
264 | self._humidity = all_result["now"]["hum"]
265 | self._pm25 = all_result["aqi"]["city"]["pm25"]
266 | self._no2 = all_result["aqi"]["city"]["no2"]
267 | self._so2 = all_result["aqi"]["city"]["so2"]
268 | self._co = all_result["aqi"]["city"]["co"]
269 | self._o3 = all_result["aqi"]["city"]["o3"]
270 | self._qlty = all_result["aqi"]["city"]["qlty"]
271 | self._updatetime = all_result["basic"]["update"]["loc"]
272 |
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/custom_components/sensor/lifesuggestion.py:
--------------------------------------------------------------------------------
1 | import logging
2 | from datetime import timedelta
3 |
4 | # 此处引入了几个异步处理的库
5 | import asyncio
6 | import async_timeout
7 | import aiohttp
8 |
9 | import voluptuous as vol
10 |
11 | # aiohttp_client将aiohttp的session与hass关联起来
12 | # track_time_interval需要使用对应的异步的版本
13 | from homeassistant.helpers.aiohttp_client import async_get_clientsession
14 | from homeassistant.helpers.event import async_track_time_interval
15 |
16 | from homeassistant.components.sensor import PLATFORM_SCHEMA
17 | from homeassistant.const import (
18 | ATTR_ATTRIBUTION)
19 | from homeassistant.helpers.entity import Entity
20 | import homeassistant.helpers.config_validation as cv
21 | import homeassistant.util.dt as dt_util
22 |
23 |
24 | _LOGGER = logging.getLogger(__name__)
25 |
26 | TIME_BETWEEN_UPDATES = timedelta(seconds=3600)
27 |
28 | CONF_OPTIONS = "options"
29 | CONF_CITY = "city"
30 | CONF_APPKEY = "appkey"
31 |
32 | # 定义多个建议选项
33 | OPTIONS = {
34 | "air": ["suggestion_air", "空气质量", "mdi:air-conditioner"],
35 | "comf": ["suggestion_comf", "体感", "mdi:human-greeting"],
36 | "cw": ["suggestion_cw", "洗车建议", "mdi:car"],
37 | "drsg": ["suggestion_drsg", "衣着建议", "mdi:hanger"],
38 | "flu": ["suggestion_flu", "感冒概率", "mdi:biohazard"],
39 | "sport": ["suggestion_sport", "运动建议", "mdi:badminton"],
40 | "trav": ["suggestion_trav", "旅行建议", "mdi:wallet-travel"],
41 | "uv": ["suggestion_uv", "防晒建议", "mdi:sunglasses"],
42 |
43 | }
44 |
45 | ATTR_UPDATE_TIME = "更新时间"
46 | ATTR_SUGGESTION = "建议"
47 | ATTRIBUTION = "来自和风天气的天气数据"
48 |
49 |
50 | PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
51 | vol.Required(CONF_CITY): cv.string,
52 | vol.Required(CONF_APPKEY): cv.string,
53 | vol.Required(CONF_OPTIONS,
54 | default=[]): vol.All(cv.ensure_list, [vol.In(OPTIONS)]),
55 | })
56 |
57 |
58 | @asyncio.coroutine
59 | def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
60 | """这个协程是程序的入口,其中add_devices函数也变成了异步版本."""
61 | _LOGGER.info("setup platform sensor.Heweather...")
62 |
63 | city = config.get(CONF_CITY)
64 | appkey = config.get(CONF_APPKEY)
65 | # 这里通过 data 实例化class SuggestionData,并传入调用API所需信息
66 | data = SuggestionData(hass, city, appkey)
67 | # 调用data实例中的异步更新函数,yield 现在我简单的理解为将后面函数变成一个生成器,减小内存占用?
68 | yield from data.async_update(dt_util.now())
69 | async_track_time_interval(hass, data.async_update, TIME_BETWEEN_UPDATES)
70 |
71 | # 根据配置文件options中的内容,添加若干个设备
72 | dev = []
73 | for option in config[CONF_OPTIONS]:
74 | dev.append(LifeSuggestion(data, option))
75 | async_add_devices(dev, True)
76 |
77 |
78 | class LifeSuggestion(Entity):
79 | """定义一个温度传感器的类,继承自HomeAssistant的Entity类."""
80 |
81 | def __init__(self, data, option):
82 | """初始化."""
83 | self._data = data
84 | self._object_id = OPTIONS[option][0]
85 | self._friendly_name = OPTIONS[option][1]
86 | self._icon = OPTIONS[option][2]
87 |
88 | self._type = option
89 | self._state = None
90 | self._updatetime = None
91 |
92 | @property
93 | def name(self):
94 | """返回实体的名字."""
95 | return self._object_id
96 |
97 | @property
98 | def registry_name(self):
99 | """返回实体的friendly_name属性."""
100 | return self._friendly_name
101 |
102 | @property
103 | def state(self):
104 | """返回当前的状态."""
105 | return self._state
106 |
107 | @property
108 | def icon(self):
109 | """返回icon属性."""
110 | return self._icon
111 |
112 | @property
113 | def device_state_attributes(self):
114 | """设置其它一些属性值."""
115 | if self._state is not None:
116 | sgt = ''
117 | if self._type == "air":
118 | sgt = self._data.air[1]
119 | elif self._type == "comf":
120 | sgt = self._data.comf[1]
121 | elif self._type == "cw":
122 | sgt = self._data.cw[1]
123 | elif self._type == "drsg":
124 | sgt = self._data.drsg[1]
125 | elif self._type == "flu":
126 | sgt = self._data.flu[1]
127 | elif self._type == "sport":
128 | sgt = self._data.sport[1]
129 | elif self._type == "trav":
130 | sgt = self._data.trav[1]
131 | elif self._type == "uv":
132 | sgt = self._data.uv[1]
133 | return {
134 | ATTR_ATTRIBUTION: ATTRIBUTION,
135 | ATTR_UPDATE_TIME: self._updatetime,
136 | ATTR_SUGGESTION: "{}".format(sgt)
137 | }
138 |
139 | @asyncio.coroutine
140 | def async_update(self):
141 | """update函数变成了async_update."""
142 | self._updatetime = self._data.updatetime
143 |
144 | if self._type == "air":
145 | self._state = self._data.air[0]
146 | elif self._type == "comf":
147 | self._state = self._data.comf[0]
148 | elif self._type == "cw":
149 | self._state = self._data.cw[0]
150 | elif self._type == "drsg":
151 | self._state = self._data.drsg[0]
152 | elif self._type == "flu":
153 | self._state = self._data.flu[0]
154 | elif self._type == "sport":
155 | self._state = self._data.sport[0]
156 | elif self._type == "trav":
157 | self._state = self._data.trav[0]
158 | elif self._type == "uv":
159 | self._state = self._data.uv[0]
160 |
161 |
162 | class SuggestionData(object):
163 | """天气相关建议的数据,存储在这个类中."""
164 |
165 | def __init__(self, hass, city, appkey):
166 | """初始化函数."""
167 | self._hass = hass
168 |
169 | self._url = "https://way.jd.com/he/freeweather"
170 | self._params = {"city": city,
171 | "appkey": appkey}
172 |
173 | self._updatetime = None
174 | self._air = None
175 | self._comf = None
176 | self._cw = None
177 | self._drsg = None
178 | self._flu = None
179 | self._sport = None
180 | self._trav = None
181 | self._uv = None
182 |
183 | @property
184 | def updatetime(self):
185 | """更新时间."""
186 | return self._updatetime
187 |
188 | @property
189 | def air(self):
190 | """通风建议."""
191 | return self._air
192 |
193 | @property
194 | def comf(self):
195 | """人体舒适度建议"""
196 | return self._comf
197 |
198 | @property
199 | def cw(self):
200 | """洗车建议"""
201 | return self._cw
202 |
203 | @property
204 | def drsg(self):
205 | """穿着建议"""
206 | return self._drsg
207 |
208 | @property
209 | def flu(self):
210 | """流感提示"""
211 | return self._flu
212 |
213 | @property
214 | def sport(self):
215 | """运动建议"""
216 | return self._sport
217 |
218 | @property
219 | def trav(self):
220 | """旅游指南"""
221 | return self._trav
222 |
223 | @property
224 | def uv(self):
225 | """防晒建议"""
226 | return self._uv
227 |
228 | @asyncio.coroutine
229 | def async_update(self, now):
230 | """从远程更新信息."""
231 | _LOGGER.info("Update from JingdongWangxiang's OpenAPI...")
232 |
233 | """
234 | # 异步模式的测试代码
235 | import time
236 | _LOGGER.info("before time.sleep")
237 | time.sleep(40)
238 | _LOGGER.info("after time.sleep and before asyncio.sleep")
239 | asyncio.sleep(40)
240 | _LOGGER.info("after asyncio.sleep and before yield from asyncio.sleep")
241 | yield from asyncio.sleep(40)
242 | _LOGGER.info("after yield from asyncio.sleep")
243 | """
244 |
245 | # 通过HTTP访问,获取需要的信息
246 | # 此处使用了基于aiohttp库的async_get_clientsession
247 | try:
248 | session = async_get_clientsession(self._hass)
249 | with async_timeout.timeout(15, loop=self._hass.loop):
250 | response = yield from session.post(
251 | self._url, data=self._params)
252 |
253 | except(asyncio.TimeoutError, aiohttp.ClientError):
254 | _LOGGER.error("Error while accessing: %s", self._url)
255 | return
256 |
257 | if response.status != 200:
258 | _LOGGER.error("Error while accessing: %s, status=%d",
259 | self._url,
260 | response.status)
261 | return
262 |
263 | result = yield from response.json()
264 |
265 | if result is None:
266 | _LOGGER.error("Request api Error")
267 | return
268 | elif result["code"] != "10000":
269 | _LOGGER.error("Error API return, code=%s, msg=%s",
270 | result["code"],
271 | result["msg"])
272 | return
273 |
274 | # 根据http返回的结果,更新数据
275 | all_result = result["result"]["HeWeather5"][0]
276 |
277 | self._updatetime = all_result["basic"]["update"]["loc"]
278 | self._air = [all_result["suggestion"]["air"]["brf"], all_result["suggestion"]["air"]["txt"]]
279 | self._comf = [all_result["suggestion"]["comf"]["brf"], all_result["suggestion"]["comf"]["txt"]]
280 | self._cw = [all_result["suggestion"]["cw"]["brf"], all_result["suggestion"]["cw"]["txt"]]
281 | self._drsg = [all_result["suggestion"]["drsg"]["brf"], all_result["suggestion"]["drsg"]["txt"]]
282 | self._flu = [all_result["suggestion"]["flu"]["brf"], all_result["suggestion"]["flu"]["txt"]]
283 | self._sport = [all_result["suggestion"]["sport"]["brf"], all_result["suggestion"]["sport"]["txt"]]
284 | self._trav = [all_result["suggestion"]["trav"]["brf"], all_result["suggestion"]["trav"]["txt"]]
285 | self._uv = [all_result["suggestion"]["uv"]["brf"], all_result["suggestion"]["uv"]["txt"]]
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/custom_components/tts/baidu.py:
--------------------------------------------------------------------------------
1 | """
2 | Baidu TTS Developer by Charley
3 | """
4 | import voluptuous as vol
5 | from homeassistant.components.tts import Provider, PLATFORM_SCHEMA, CONF_LANG
6 | import homeassistant.helpers.config_validation as cv
7 |
8 | import requests
9 | import logging
10 | import json
11 |
12 | _Log=logging.getLogger(__name__)
13 |
14 | # 默认语言
15 | DEFAULT_LANG = 'zh'
16 |
17 | # 支持的语言
18 | SUPPORT_LANGUAGES = [
19 | 'zh',
20 | ]
21 |
22 | CONF_APIKEY = 'api_key'
23 | CONF_SECRETKEY = 'secret_key'
24 | CONF_SPEED = 'speed'
25 | CONF_PITCH = 'pitch'
26 | CONF_VOLUME = 'volume'
27 | PERSON = 'person'
28 |
29 |
30 | TOKEN_INTERFACE = 'https://openapi.baidu.com/oauth/2.0/token'
31 | TEXT2AUDIO_INTERFACE = 'http://tsn.baidu.com/text2audio'
32 |
33 | PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
34 | vol.Optional(CONF_LANG, default=DEFAULT_LANG): vol.In(SUPPORT_LANGUAGES),
35 | vol.Optional(CONF_APIKEY): cv.string,
36 | vol.Optional(CONF_SECRETKEY):cv.string,
37 | vol.Optional(CONF_SPEED,default='5'): cv.string,
38 | vol.Optional(CONF_PITCH,default='5'): cv.string,
39 | vol.Optional(CONF_VOLUME,default='5'): cv.string,
40 | vol.Optional(PERSON,default='0'): cv.string,
41 | })
42 |
43 | def get_engine(hass, config):
44 | lang = config.get(CONF_LANG)
45 | apiKey = config.get(CONF_APIKEY)
46 | secretKey = config.get(CONF_SECRETKEY)
47 | speed = config.get(CONF_SPEED)
48 | pitch = config.get(CONF_PITCH)
49 | volume = config.get(CONF_VOLUME)
50 | person = config.get(PERSON)
51 |
52 | if apiKey == None:
53 | _Log.error('Api Key is nil')
54 | return False
55 | if secretKey == None:
56 | _Log.error('secretKey is nil')
57 | return False
58 |
59 | return BaiduTTS(lang,apiKey,secretKey,speed,pitch,volume,person)
60 |
61 | class BaiduTTS (Provider):
62 |
63 | def __init__(self,lang,apiKey,secretKey,speed,pitch,volume,person):
64 | self._lang = lang
65 | self._apiKey = apiKey
66 | self._secretKey = secretKey
67 | self._speed = speed
68 | self._pitch = pitch
69 | self._volume = volume
70 | self._person = person
71 | token = self.getToken()
72 | _Log.info("token =====>" + token)
73 | self._Token = token
74 |
75 | def getToken(self):
76 | resp = requests.get(TOKEN_INTERFACE,params={'grant_type': 'client_credentials','client_id':self._apiKey,'client_secret':self._secretKey})
77 | if resp.status_code != 200:
78 | _Log.error('Get ToKen Http Error status_code:%s' % resp.status_code)
79 | return None
80 | resp.encoding = 'utf-8'
81 | # toKenjsonStr = resp.text
82 | tokenJson = resp.json()
83 |
84 | if not 'access_token' in tokenJson:
85 | _Log.error('Get ToKen Json Error!')
86 | return None
87 | return tokenJson['access_token']
88 |
89 | @property
90 | def default_language(self):
91 | """Default language."""
92 | return self._lang
93 |
94 | @property
95 | def supported_languages(self):
96 | """List of supported languages."""
97 | return SUPPORT_LANGUAGES
98 |
99 | def get_tts_audio(self, message, language, options=None):
100 | if self._Token == None:
101 | self._Token = self.getToken()
102 |
103 | if self._Token == None:
104 | _Log.error('get_tts_audio Self.ToKen is nil')
105 | return
106 |
107 | resp = requests.get(TEXT2AUDIO_INTERFACE,params={'tex':message,'lan':language,'tok':self._Token,'ctp':'1','cuid':'HomeAssistant','spd':self._speed,'pit':self._pitch,'vol':self._volume,'per':self._person})
108 |
109 | if resp.status_code == 500:
110 | _Log.error('Text2Audio Error:500 Not Support.')
111 | return
112 | if resp.status_code == 501:
113 | _Log.error('Text2Audio Error:501 Params Error')
114 | return
115 | if resp.status_code == 502:
116 | _Log.error('Text2Audio Error:502 TokenVerificationError.')
117 | _Log.Info('Now Get Token!')
118 | self._Token = self.getToken()
119 | self.get_tts_audio(message,language,options)
120 | return
121 | if resp.status_code == 503:
122 | _Log.error('Text2Audio Error:503 Composite Error.')
123 | return
124 |
125 | if resp.status_code != 200:
126 | _Log.error('get_tts_audio Http Error status_code:%s' % resp.status_code)
127 | return
128 |
129 | data = resp.content
130 | return ('mp3',data)
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/customize.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/customize.yaml
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/groups.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/groups.yaml
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/packages/cloudmusic.yaml:
--------------------------------------------------------------------------------
1 | panel_custom:
2 | - name: cloudmusic
3 | sidebar_title: 云音乐
4 | sidebar_icon: mdi:music
5 | url_path: music
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/packages/heweather.yaml:
--------------------------------------------------------------------------------
1 | sensor:
2 | - platform: heweather
3 | city: 上海
4 | appkey: 41d02a36c1c9455ab84e3334a4623021
5 | options:
6 | - temprature
7 | - humidity
8 | - pm25
9 | - no2
10 | - so2
11 | - co
12 | - o3
13 | - qlty
14 |
15 | - platform: heweather_hourlyforecast
16 | city: 上海
17 | appkey: 41d02a36c1c9455ab84e3334a4623021
18 | options:
19 | - 3hour
20 | - 6hour
21 | - 9hour
22 |
23 | group:
24 | heweatherAQI:
25 | view: no
26 | name: 空气质量
27 | entities:
28 | #- sensor.sensor.heweather_humidity
29 | #- sensor.heweather_temperature
30 | - sensor.heweather_qlty
31 | - sensor.heweather_no2
32 | - sensor.heweather_pm25
33 | - sensor.heweather_co
34 | - sensor.heweather_so2
35 | - sensor.heweather_o3
36 | hourlyforecast:
37 | view: no
38 | name: 小时天气预报
39 | entities:
40 | - sensor.hourly_forcast_3
41 | - sensor.hourly_forcast_6
42 | - sensor.hourly_forcast_9
43 |
44 |
45 |
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/packages/my_switch.yaml:
--------------------------------------------------------------------------------
1 | switch:
2 | platform: command_line
3 | switches:
4 | kodi:
5 | friendly_name: 机顶盒
6 | command_off: "killall kodi"
7 | command_on: "su - pi -c 'kodi'"
8 | motion:
9 | friendly_name: 视频监控
10 | command_off: "killall motion"
11 | command_on: "motion -b"
12 | home_assistant_system_shutdown:
13 | friendly_name: pi关机
14 | command_off: "sudo poweroff"
15 | command_state: "echo 0"
16 | pi_restart:
17 | friendly_name: pi重启
18 | command_off: "sudo reboot"
19 | command_state: "echo 0"
20 | pi_usb_mount:
21 | friendly_name: 挂载硬盘
22 | command_off: "sudo umount /home/pi/share/my_usb"
23 | command_on: "sudo mount /dev/sda1 /home/pi/share/my_usb -w"
24 | pi_baiduyun:
25 | friendly_name: 百度云同步
26 | command_off: "killall bypy"
27 | command_on: "bypy syncdown / /home/pi/share/my_usb/ >> /home/pi/share/my_usb/sync.log &"
28 |
29 | group:
30 | switch1:
31 | name: 开关组
32 | view: no
33 | entities:
34 | - switch.home_assistant_system_shutdown
35 | - switch.motion
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/packages/phicomm_dc1m.yaml:
--------------------------------------------------------------------------------
1 | switch:
2 | - platform: phicomm_dc1m
3 | name: dc1
4 | hidden: true
5 | ip: "192.168.2.129"
6 | ports: {'1':'dc1_s1','2':'dc1_s2','3':'dc1_s3'}
7 | - platform: phicomm_dc1m
8 | name: dc1_2
9 | hidden: true
10 | ip: "192.168.2.122"
11 | ports: {'1':'dc1_2_s1','2':'dc1_2_s2','3':'dc1_2_s3'}
12 | - platform: template
13 | switches:
14 | dc1_template:
15 | friendly_name: 总开关
16 | value_template: "{{ is_state('switch.dc1', 'on') }}"
17 | turn_on:
18 | service: switch.turn_on
19 | data:
20 | entity_id: switch.dc1
21 | turn_off:
22 | service: switch.turn_off
23 | data:
24 | entity_id: switch.dc1
25 | dc1_s1_template:
26 | friendly_name: 路由器
27 | value_template: "{{ is_state('switch.dc1_s1', 'on') }}"
28 | turn_on:
29 | service: switch.turn_on
30 | data:
31 | entity_id: switch.dc1_s1
32 | turn_off:
33 | service: switch.turn_off
34 | data:
35 | entity_id: switch.dc1_s1
36 | dc1_s2_template:
37 | friendly_name: 中间
38 | value_template: "{{ is_state('switch.dc1_s2', 'on') }}"
39 | turn_on:
40 | service: switch.turn_on
41 | data:
42 | entity_id: switch.dc1_s2
43 | turn_off:
44 | service: switch.turn_off
45 | data:
46 | entity_id: switch.dc1_s2
47 | dc1_s3_template:
48 | friendly_name: 树莓派
49 | value_template: "{{ is_state('switch.dc1_s3', 'on') }}"
50 | turn_on:
51 | service: switch.turn_on
52 | data:
53 | entity_id: switch.dc1_s3
54 | turn_off:
55 | service: switch.turn_off
56 | data:
57 | entity_id: switch.dc1_s3
58 | sensor:
59 | - platform: template
60 | sensors:
61 | dc1_v:
62 | friendly_name: 当前电压
63 | value_template: "{{ states.switch.dc1.attributes.v }}"
64 | unit_of_measurement: V
65 | dc1_p:
66 | friendly_name: 当前功率
67 | value_template: "{{ states.switch.dc1.attributes.p }}"
68 | unit_of_measurement: W
69 | dc1_2_v:
70 | friendly_name: 当前电压
71 | value_template: "{{ states.switch.dc1_2.attributes.v }}"
72 | unit_of_measurement: V
73 | dc1_2_p:
74 | friendly_name: 当前功率
75 | value_template: "{{ states.switch.dc1_2.attributes.p }}"
76 | unit_of_measurement: W
77 | # dc1_totale:
78 | # friendly_name: 累计用电
79 | # value_template: "{{ states.switch.dc1.attributes.totalelect }}"
80 | # unit_of_measurement: 度
81 | group:
82 | dc1:
83 | name: 工作区DC1排插
84 | view: no
85 | entities:
86 | - sensor.dc1_v
87 | - sensor.dc1_p
88 | #- sensor.dc1_totale
89 | - switch.dc1_template
90 | - switch.dc1_s1_template
91 | - switch.dc1_s2_template
92 | - switch.dc1_s3_template
93 | dc1_2:
94 | name: DC1排插2
95 | view: no
96 | entities:
97 | - sensor.dc1_2_v
98 | - sensor.dc1_2_p
99 | #- sensor.dc1_totale
100 | - switch.dc1_2
101 | - switch.dc1_2_s1
102 | - switch.dc1_2_s2
103 | - switch.dc1_2_s3
104 | homeassistant:
105 | customize:
106 | # Add an entry for each entity that you want to overwrite.
107 | switch.dc1:
108 | hidden: true
109 | switch.dc1_s1:
110 | hidden: true
111 | switch.dc1_s2:
112 | hidden: true
113 | switch.dc1_s3:
114 | hidden: true
115 |
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/packages/suggest.yaml:
--------------------------------------------------------------------------------
1 | sensor:
2 | - platform: lifesuggestion
3 | city: 上海
4 | appkey: 41d02a36c1c9455ab84e3334a4623021
5 | options:
6 | - air
7 | - comf
8 | - cw
9 | - drsg
10 | - flu
11 | - sport
12 | - trav
13 | - uv
14 |
15 | group:
16 | suggestion:
17 | view: no
18 | name: 品质生活
19 | entities:
20 | - sensor.suggestion_air
21 | - sensor.suggestion_comf
22 | - sensor.suggestion_cw
23 | - sensor.suggestion_drsg
24 | - sensor.suggestion_flu
25 | - sensor.suggestion_sport
26 | - sensor.suggestion_trav
27 | - sensor.suggestion_uv
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/packages/switch_group.yaml.bak:
--------------------------------------------------------------------------------
1 | switch:
2 | platform: command_line
3 | switches:
4 | kodi:
5 | friendly_name: 机顶盒
6 | command_off: "killall kodi"
7 | command_on: "su - pi -c 'kodi'"
8 | motion:
9 | friendly_name: 视频监控
10 | command_off: "killall motion"
11 | command_on: "motion -b"
12 | home_assistant_system_shutdown:
13 | friendly_name: pi关机
14 | command_off: "sudo poweroff"
15 | command_state: "echo 0"
16 | pi_restart:
17 | friendly_name: pi重启
18 | command_off: "sudo reboot"
19 | command_state: "echo 0"
20 | pi_usb_mount:
21 | friendly_name: 挂载硬盘
22 | command_off: "sudo umount /home/pi/share/my_usb"
23 | command_on: "sudo mount /dev/sda1 /home/pi/share/my_usb -w"
24 | pi_baiduyun:
25 | friendly_name: 百度云同步
26 | command_off: "killall bypy"
27 | command_on: "bypy syncdown / /home/pi/share/my_usb/ >> /home/pi/share/my_usb/sync.log &"
28 |
29 | group:
30 | switch1:
31 | name: 开关组
32 | view: no
33 | entities:
34 | - switch.home_assistant_system_shutdown
35 | - switch.motion
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/packages/weather.yaml:
--------------------------------------------------------------------------------
1 | weather:
2 | - platform: heweather_forecast
3 | city: 上海
4 | appkey: 41d02a36c1c9455ab84e3334a4623021
5 |
6 |
7 | group:
8 | weather:
9 | view: no
10 | name: 本地天气
11 | entities:
12 | - weather.localweather
--------------------------------------------------------------------------------
/homeassistant/.homeassistant/panels/cloudmusic.html:
--------------------------------------------------------------------------------
1 |
'+(n.content||"")+"
"),n.skin&&(n.anim="up"),"msg"===n.skin&&(n.shade=!1),s.innerHTML=(n.shade?"':"")+'