├── .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 | 2 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /homeassistant/.homeassistant/scripts.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/scripts.yaml -------------------------------------------------------------------------------- /homeassistant/.homeassistant/secrets.yaml: -------------------------------------------------------------------------------- 1 | 2 | # Use this file to store secrets like usernames and passwords. 3 | # Learn more at https://home-assistant.io/docs/configuration/secrets/ 4 | http_password: welcome 5 | -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/custom_ui/state-card-custom-ui-es5.html.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/custom_ui/state-card-custom-ui-es5.html.gz -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/custom_ui/state-card-custom-ui.html.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/custom_ui/state-card-custom-ui.html.gz -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/cache/index.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/music/cache/index.html -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/css/small.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | /************************************************** 3 | * MKOnlinePlayer v2.31 4 | * 小屏幕样式修复 5 | * 编写:mengkun(http://mkblog.cn) 6 | * 时间:2017-9-13 7 | *************************************************/ 8 | 9 | /* 小于 900px 采用这个样式 */ 10 | @media screen and (max-width: 900px) { 11 | /*隐藏头部logo*/ 12 | .header { 13 | display: none; 14 | } 15 | /*中部顶格*/ 16 | .center { 17 | top: 0; 18 | } 19 | 20 | /* 调出播放器按钮 */ 21 | .btn[data-action='player'] { 22 | display: inline-block; 23 | } 24 | 25 | /* 按钮工具条区域 */ 26 | .btn-bar { 27 | height: 35px; 28 | right: 0; 29 | z-index: 999; 30 | } 31 | .btn-box { 32 | background-color: #000; 33 | background-color: rgba(0, 0, 0, 0.12); 34 | position: absolute; 35 | top: 0; 36 | bottom: 0; 37 | left: 0; 38 | right: 0; 39 | } 40 | .btn { 41 | margin: 0; 42 | padding: 0; 43 | width: 25%; 44 | height: 100%; 45 | display: block; 46 | float: left; 47 | border: none; 48 | text-align: center; 49 | line-height: 35px; 50 | color: #C5C5C5; 51 | } 52 | .btn:hover { 53 | border: none; 54 | } 55 | .btn-box .active:after { 56 | content: ''; 57 | display: block; 58 | border-bottom: 3px solid #A2A0A0; 59 | margin-top: -3px; 60 | } 61 | 62 | /* 中部容器区域 */ 63 | .data-area { 64 | top: 40px; 65 | } 66 | 67 | /*数据区域占满整个屏幕*/ 68 | .data-area { 69 | right: 0; 70 | } 71 | 72 | 73 | /*列表菜单不显示*/ 74 | .list-menu { 75 | display: none!important; 76 | } 77 | .music-name-cult { 78 | padding-right: 0!important; 79 | } 80 | 81 | /* 专辑区域腾出位置 */ 82 | .music-album { 83 | margin-right: 30px; 84 | } 85 | /* 小屏幕的列表菜单 */ 86 | .list-mobile-menu { 87 | position: absolute; 88 | display: block; 89 | width: 30px; 90 | height: 30px; 91 | background-image: url(../images/player.png); 92 | background-position: -30px -365px; 93 | right: 0; 94 | top: 50%; 95 | -webkit-transform: translateY(-50%); 96 | -moz-transform: translateY(-50%); 97 | -ms-transform: translateY(-50%); 98 | -o-transform: translateY(-50%); 99 | transform: translateY(-50%); 100 | z-index: 2; 101 | cursor: pointer; 102 | } 103 | 104 | /*控制按钮区域缩小*/ 105 | .con-btn { 106 | width: 120px; 107 | } 108 | /*进度条调整*/ 109 | .progress { 110 | width: auto; 111 | margin-left: 130px; 112 | margin-right: 10px; 113 | height: 100%; 114 | position: relative; 115 | } 116 | .progress-box { 117 | right: 40px; 118 | } 119 | .airplayer { 120 | left: 0px; 121 | } 122 | /*音量控制区域隐藏*/ 123 | .vol { 124 | display: none; 125 | } 126 | 127 | /*隐藏右侧歌词及封面*/ 128 | .player { 129 | display: none; 130 | width: 100%; 131 | } 132 | .cover { 133 | margin-top: 60px; 134 | } 135 | #lyric { 136 | overflow-x: hidden; 137 | overflow-y: auto; 138 | } 139 | .lyric { 140 | top: 260px; 141 | } 142 | } 143 | 144 | /* 小于 620px 采用这个样式 */ 145 | @media screen and (max-width: 620px) { 146 | /*专辑信息不显示*/ 147 | .music-album { 148 | display: none; 149 | } 150 | /*歌手名字*/ 151 | .auth-name { 152 | width: 35%; 153 | padding-right: 30px; 154 | box-sizing: border-box; 155 | } 156 | /*音乐名字拉长*/ 157 | .music-name { 158 | margin-right: 35%; 159 | } 160 | } 161 | 162 | /* 小于 500px 采用这个样式 */ 163 | @media screen and (max-width: 500px) { 164 | .center { 165 | bottom: 60px; 166 | } 167 | /* 歌单封面 */ 168 | .sheet-item { 169 | width: 33.33%; 170 | } 171 | /* 歌单名字 */ 172 | .sheet-name { 173 | max-width: 100px; 174 | } 175 | .cover { 176 | margin-top: 50px; 177 | } 178 | .footer { 179 | height: 60px; 180 | } 181 | } 182 | 183 | /* 小于 350px 采用这个样式 */ 184 | @media screen and (max-width: 350px) { 185 | /* 歌单封面 */ 186 | .sheet-item { 187 | width: 50%; 188 | } 189 | } -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/images/airplayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/music/images/airplayer.png -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/images/album_cover_player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/music/images/album_cover_player.png -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/images/go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/music/images/go.png -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/images/history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/music/images/history.png -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/images/icon_list_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/music/images/icon_list_menu.png -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/music/images/loading.gif -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/images/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/music/images/player.png -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/images/player_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/music/images/player_cover.png -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/images/wave.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/music/images/wave.gif -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 家庭云音乐中心 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 | 52 | 53 | 58 | 59 | 60 |
61 |
62 |
63 | 64 |
65 | 66 | 正在播放 67 | 播放列表 68 | 歌曲搜索 69 |
70 |
71 | 72 |
73 | 74 | 75 | 76 | 77 |
78 |
79 | 80 | 81 |
82 | 83 |
84 | 85 |
86 | 87 |
88 |
    89 |
    90 |
    91 |
    92 |
    93 |
    94 | 95 | 96 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/js/airplay.js: -------------------------------------------------------------------------------- 1 | $(".progress").on("click",".btn-airplayer", function() { 2 | states(); 3 | layer.open({ 4 | type: 1, 5 | title: "选择播放设备", 6 | skin: 'layui-layer-demo', 7 | area: ['250px', '200px'], 8 | closeBtn: 0, 9 | anim: 2, 10 | shadeClose: true, 11 | fixed: true, 12 | resize: false, 13 | content: $('.player-list') 14 | }); 15 | }); 16 | 17 | var storage=window.localStorage; 18 | var tokens = JSON.parse(storage.getItem("hassTokens")); 19 | var timer=null; 20 | var s=0; 21 | 22 | function states(){ 23 | $.ajax({ 24 | type: "GET", 25 | url: "/api/states", 26 | beforeSend: function(request) { 27 | request.setRequestHeader("authorization", tokens.token_type + " " + tokens.access_token); 28 | }, 29 | success: function(result) { 30 | var json = eval(result); 31 | var players = ""; 32 | var curPlayer = storage.getItem("curPlayer"); 33 | $.each(result, function (i) { 34 | var entity_id = json[i].entity_id; 35 | var friendly_name = json[i].attributes.friendly_name; 36 | if(entity_id.indexOf("media_player.") >= 0 ) { 37 | var cur = entity_id == curPlayer ? ' class="cur"' : ''; 38 | players += ''+friendly_name+''; 39 | } 40 | }); 41 | var curif = (curPlayer==undefined || curPlayer==0) ? ' class="cur"' : ''; 42 | rem.playerList.html('本机'+players); 43 | $(".player-list li").bind("click",function(){ 44 | var entityId = $(this).attr('entity_id'); 45 | var last_entityId = storage.getItem("curPlayer"); 46 | storage.setItem("curPlayer",entityId); 47 | $(this).addClass("cur").siblings().removeClass("cur"); 48 | if(entityId == 0){ 49 | clearInterval(timer); 50 | player_op(last_entityId,"media_play_pause"); 51 | } 52 | var playingid = $(".list-playing").attr('data-no'); 53 | if(playingid>=0){ 54 | clearInterval(timer); 55 | playList(playingid); 56 | //play_media(entityId,playingid); 57 | } 58 | }); 59 | } 60 | }); 61 | } 62 | 63 | function play_media(entityId,mediaId){ 64 | var musicUrl = (mediaId.indexOf("http://") >= 0) ? mediaId : musicList[1].item[mediaId].url; 65 | $.ajax({ 66 | type: "POST", 67 | url: "/api/services/media_player/play_media", 68 | data: '{"entity_id": "'+ entityId +'","media_content_id":"'+ musicUrl +'","media_content_type":"music"}', 69 | beforeSend: function(request) { 70 | request.setRequestHeader("authorization", tokens.token_type + " " + tokens.access_token); 71 | }, 72 | success: function(result){ 73 | clearInterval(timer); 74 | audioPlay(); 75 | update_bar(0,rem.audio[0].duration); 76 | //console.log(rem.audio[0].duration); 77 | //setTimeout(function() {clearInterval(timer);update_bar(10,play_states(storage.getItem("curPlayer")));},10000); 78 | } 79 | }); 80 | } 81 | 82 | function player_op(entityId,op){ 83 | $.ajax({ 84 | type: "POST", 85 | url: "/api/services/media_player/"+ op, 86 | data: '{"entity_id": "'+ entityId +'"}', 87 | beforeSend: function(request) { 88 | request.setRequestHeader("authorization", tokens.token_type + " " + tokens.access_token); 89 | }, 90 | success: function(result){ 91 | 92 | } 93 | }); 94 | } 95 | 96 | function player_volset(entityId,volume_level){ 97 | $.ajax({ 98 | type: "POST", 99 | url: "/api/services/media_player/volume_set", 100 | data: '{"entity_id": "'+ entityId +'","volume_level": "'+ volume_level +'"}', 101 | beforeSend: function(request) { 102 | request.setRequestHeader("authorization", tokens.token_type + " " + tokens.access_token); 103 | }, 104 | success: function(result){ 105 | } 106 | }); 107 | } 108 | 109 | function update_bar(media_position,media_duration){ 110 | s = media_position; 111 | timer = setInterval(function(){ 112 | s++; 113 | music_bar.lock(true); 114 | music_bar.goto(s / media_duration); 115 | scrollLyric(s); 116 | if(s == parseInt(media_duration)){ 117 | autoNextMusic(); 118 | clearInterval(timer); 119 | } 120 | },1000); 121 | } 122 | 123 | function play_states(entityId){ 124 | var media_duration = 0; 125 | $.ajax({ 126 | type: "GET", 127 | url: "/api/states/"+ entityId +"?r="+Math.random(), 128 | async:false, 129 | beforeSend: function(request) { 130 | request.setRequestHeader("authorization", tokens.token_type + " " + tokens.access_token); 131 | }, 132 | success: function(result){ 133 | media_duration = result.attributes.media_duration; 134 | storage.setItem("curMedia_duration",media_duration); 135 | } 136 | }); 137 | return media_duration; 138 | } -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/js/background-blur.min.js: -------------------------------------------------------------------------------- 1 | !function(t){"use strict";function e(e){return this.each(function(){var i=t(this),n=i.data("plugin.backgroundBlur"),o=t.extend({},r.DEFAULTS,i.data(),"object"==typeof e&&e);n||i.data("plugin.backgroundBlur",n=new r(this,o)),"fadeIn"===e?n.fadeIn():"fadeOut"===e?n.fadeOut():"string"==typeof e&&n.generateBlurredImage(e)})}var i=function(){for(var t,e=3,i=document.createElement("div"),n=i.getElementsByTagName("i");i.innerHTML="",n[0];);return e>4?e:t}(),n=function(){return"_"+Math.random().toString(36).substr(2,9)},o={svgns:"http://www.w3.org/2000/svg",xlink:"http://www.w3.org/1999/xlink",createElement:function(t,e){var i=document.createElementNS(o.svgns,t);return e&&o.setAttr(i,e),i},setAttr:function(t,e){for(var i in e)"href"===i?t.setAttributeNS(o.xlink,i,e[i]):t.setAttribute(i,e[i]);return t}},r=function(e,i){this.internalID=n(),this.$element=t(e),this.$width=this.$element.width(),this.$height=this.$element.height(),this.element=e,this.options=t.extend({},r.DEFAULTS,i),this.$overlayEl=this.createOverlay(),this.$blurredImage={},this.useVelocity=this.detectVelocity(),this.attachListeners(),this.generateBlurredImage(this.options.imageURL)};r.VERSION="0.0.1",r.DEFAULTS={imageURL:"",blurAmount:10,imageClass:"",overlayClass:"",duration:!1,opacity:1},r.prototype.detectVelocity=function(){return!!window.jQuery.Velocity},r.prototype.attachListeners=function(){this.$element.on("ui.blur.loaded",t.proxy(this.fadeIn,this)),this.$element.on("ui.blur.unload",t.proxy(this.fadeOut,this))},r.prototype.fadeIn=function(){this.options.duration&&this.options.duration>0&&(this.useVelocity?this.$blurredImage.velocity({opacity:this.options.opacity},{duration:this.options.duration}):this.$blurredImage.animate({opacity:this.options.opacity},{duration:this.options.duration}))},r.prototype.fadeOut=function(){this.options.duration&&this.options.duration>0?this.useVelocity?this.$blurredImage.velocity({opacity:0},{duration:this.options.duration}):this.$blurredImage.animate({opacity:0},{duration:this.options.duration}):this.$blurredImage.css({opacity:0})},r.prototype.generateBlurredImage=function(t){var e=this.$blurredImage;this.internalID=n(),e.length>0&&(this.options.duration&&this.options.duration>0?this.useVelocity?e.first().velocity({opacity:0},{duration:this.options.duration,complete:function(){e.remove()}}):e.first().animate({opacity:0},{duration:this.options.duration,complete:function(){e.remove()}}):e.remove()),this.$blurredImage=i?this.createIMG(t,this.$width,this.$height):this.createSVG(t,this.$width,this.$height)},r.prototype.createOverlay=function(){return this.options.overlayClass&&""!==this.options.overlayClass?t("
    ").prependTo(this.$element).addClass(this.options.overlayClass):!1},r.prototype.createSVG=function(e,i,n){var r=this,s=o.createElement("svg",{xmlns:o.svgns,version:"1.1",width:i,height:n,id:"blurred"+this.internalID,"class":this.options.imageClass,viewBox:"0 0 "+i+" "+n,preserveAspectRatio:"none"}),a="blur"+this.internalID,u=o.createElement("filter",{id:a}),l=o.createElement("feGaussianBlur",{"in":"SourceGraphic",stdDeviation:this.options.blurAmount}),h=o.createElement("image",{x:0,y:0,width:i,height:n,externalResourcesRequired:"true",href:e,style:"filter:url(#"+a+")",preserveAspectRatio:"none"});h.addEventListener("load",function(){r.$element.trigger("ui.blur.loaded")},!0),h.addEventListener("SVGLoad",function(){r.$element.trigger("ui.blur.loaded")},!0),u.appendChild(l),s.appendChild(u),s.appendChild(h);var d=t(s);return r.options.duration&&r.options.duration>0&&(d.css({opacity:0}),window.setTimeout(function(){"0"===d.css("opacity")&&d.css({opacity:1})},this.options.duration+100)),this.element.insertBefore(s,this.element.firstChild),d},r.prototype.createIMG=function(t,e,i){var n=this,o=this.prependImage(t),r=2*this.options.blurAmount>100?100:2*this.options.blurAmount;return o.css({filter:"progid:DXImageTransform.Microsoft.Blur(pixelradius="+r+") ",top:2.5*-this.options.blurAmount,left:2.5*-this.options.blurAmount,width:e+2.5*this.options.blurAmount,height:i+2.5*this.options.blurAmount}).attr("id","blurred"+this.internalID),o.load(function(){n.$element.trigger("ui.blur.loaded")}),this.options.duration&&this.options.duration>0&&window.setTimeout(function(){"0"===o.css("opacity")&&o.css({opacity:1})},this.options.duration+100),o},r.prototype.prependImage=function(e){var i,n=t('');return i=this.$overlayEl?n.insertBefore(this.$overlayEl).attr("id",this.internalID).addClass(this.options.imageClass):n.prependTo(this.$element).attr("id",this.internalID).addClass(this.options.imageClass)};var s=t.fn.backgroundBlur;t.fn.backgroundBlur=e,t.fn.backgroundBlur.Constructor=r,t.fn.backgroundBlur.noConflict=function(){return t.fn.backgroundBlur=s,this}}(jQuery); -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/js/lyric.js: -------------------------------------------------------------------------------- 1 | /************************************************** 2 | * MKOnlinePlayer v2.31 3 | * 歌词解析及滚动模块 4 | * 编写:mengkun(http://mkblog.cn) 5 | * 时间:2017-9-13 6 | *************************************************/ 7 | 8 | var lyricArea = $("#lyric"); // 歌词显示容器 9 | 10 | // 在歌词区显示提示语(如歌词加载中、无歌词等) 11 | function lyricTip(str) { 12 | lyricArea.html("
  • "+str+"
  • "); // 显示内容 13 | } 14 | 15 | // 歌曲加载完后的回调函数 16 | // 参数:歌词源文件 17 | function lyricCallback(str, id) { 18 | if(id !== musicList[rem.playlist].item[rem.playid].id) return; // 返回的歌词不是当前这首歌的,跳过 19 | 20 | rem.lyric = parseLyric(str); // 解析获取到的歌词 21 | 22 | if(rem.lyric === '') { 23 | lyricTip('没有歌词'); 24 | return false; 25 | } 26 | 27 | lyricArea.html(''); // 清空歌词区域的内容 28 | lyricArea.scrollTop(0); // 滚动到顶部 29 | 30 | rem.lastLyric = -1; 31 | 32 | // 显示全部歌词 33 | var i = 0; 34 | for(var k in rem.lyric){ 35 | var txt = rem.lyric[k]; 36 | if(!txt) txt = " "; 37 | var li = $("
  • "+txt+"
  • "); 38 | lyricArea.append(li); 39 | i++; 40 | } 41 | } 42 | 43 | // 强制刷新当前时间点的歌词 44 | // 参数:当前播放时间(单位:秒) 45 | function refreshLyric(time) { 46 | if(rem.lyric === '') return false; 47 | 48 | time = parseInt(time); // 时间取整 49 | var i = 0; 50 | for(var k in rem.lyric){ 51 | if(k >= time) break; 52 | i = k; // 记录上一句的 53 | } 54 | 55 | scrollLyric(i); 56 | } 57 | 58 | // 滚动歌词到指定句 59 | // 参数:当前播放时间(单位:秒) 60 | function scrollLyric(time) { 61 | if(rem.lyric === '') return false; 62 | 63 | time = parseInt(time); // 时间取整 64 | 65 | if(rem.lyric === undefined || rem.lyric[time] === undefined) return false; // 当前时间点没有歌词 66 | 67 | if(rem.lastLyric == time) return true; // 歌词没发生改变 68 | 69 | var i = 0; // 获取当前歌词是在第几行 70 | for(var k in rem.lyric){ 71 | if(k == time) break; 72 | i ++; 73 | } 74 | rem.lastLyric = time; // 记录方便下次使用 75 | $(".lplaying").removeClass("lplaying"); // 移除其余句子的正在播放样式 76 | $(".lrc-item[data-no='" + i + "']").addClass("lplaying"); // 加上正在播放样式 77 | 78 | var scroll = (lyricArea.children().height() * i) - ($(".lyric").height() / 2); 79 | lyricArea.stop().animate({scrollTop: scroll}, 1000); // 平滑滚动到当前歌词位置(更改这个数值可以改变歌词滚动速度,单位:毫秒) 80 | 81 | } 82 | 83 | // 解析歌词 84 | // 这一函数来自 https://github.com/TivonJJ/html5-music-player 85 | // 参数:原始歌词文件 86 | function parseLyric(lrc) { 87 | if(lrc === '') return ''; 88 | var lyrics = lrc.split("\n"); 89 | var lrcObj = {}; 90 | for(var i=0;i 4 | * @link http://overtrue.me 5 | * @version 2.2 6 | --> 7 | 8 | 9 | 10 | 11 | 不支持的浏览器 12 | 13 | 14 | 15 | 16 | 84 | 85 |
    86 |
    87 |
    88 |
    89 | 106 |
    107 |
    108 | 109 | -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/plugns/layer/mobile/layer.js: -------------------------------------------------------------------------------- 1 | /*! layer mobile-v2.0.0 Web弹层组件 MIT License http://layer.layui.com/mobile By 贤心 */ 2 | ;!function(e){"use strict";var t=document,n="querySelectorAll",i="getElementsByClassName",a=function(e){return t[n](e)},s={type:0,shade:!0,shadeClose:!0,fixed:!0,anim:"scale"},l={extend:function(e){var t=JSON.parse(JSON.stringify(s));for(var n in e)t[n]=e[n];return t},timer:{},end:{}};l.touch=function(e,t){e.addEventListener("click",function(e){t.call(this,e)},!1)};var r=0,o=["layui-m-layer"],c=function(e){var t=this;t.config=l.extend(e),t.view()};c.prototype.view=function(){var e=this,n=e.config,s=t.createElement("div");e.id=s.id=o[0]+r,s.setAttribute("class",o[0]+" "+o[0]+(n.type||0)),s.setAttribute("index",r);var l=function(){var e="object"==typeof n.title;return n.title?'

    '+(e?n.title[0]:n.title)+"

    ":""}(),c=function(){"string"==typeof n.btn&&(n.btn=[n.btn]);var e,t=(n.btn||[]).length;return 0!==t&&n.btn?(e=''+n.btn[0]+"",2===t&&(e=''+n.btn[1]+""+e),'
    '+e+"
    "):""}();if(n.fixed||(n.top=n.hasOwnProperty("top")?n.top:100,n.style=n.style||"",n.style+=" top:"+(t.body.scrollTop+n.top)+"px"),2===n.type&&(n.content='

    '+(n.content||"")+"

    "),n.skin&&(n.anim="up"),"msg"===n.skin&&(n.shade=!1),s.innerHTML=(n.shade?"
    ':"")+'
    "+l+'
    '+n.content+"
    "+c+"
    ",!n.type||2===n.type){var d=t[i](o[0]+n.type),y=d.length;y>=1&&layer.close(d[0].getAttribute("index"))}document.body.appendChild(s);var u=e.elem=a("#"+e.id)[0];n.success&&n.success(u),e.index=r++,e.action(n,u)},c.prototype.action=function(e,t){var n=this;e.time&&(l.timer[n.index]=setTimeout(function(){layer.close(n.index)},1e3*e.time));var a=function(){var t=this.getAttribute("type");0==t?(e.no&&e.no(),layer.close(n.index)):e.yes?e.yes(n.index):layer.close(n.index)};if(e.btn)for(var s=t[i]("layui-m-layerbtn")[0].children,r=s.length,o=0;odiv{line-height:22px;padding-top:7px;margin-bottom:20px;font-size:14px}.layui-m-layerbtn{display:box;display:-moz-box;display:-webkit-box;width:100%;height:50px;line-height:50px;font-size:0;border-top:1px solid #D0D0D0;background-color:#F2F2F2}.layui-m-layerbtn span{display:block;-moz-box-flex:1;box-flex:1;-webkit-box-flex:1;font-size:14px;cursor:pointer}.layui-m-layerbtn span[yes]{color:#40AFFE}.layui-m-layerbtn span[no]{border-right:1px solid #D0D0D0;border-radius:0 0 0 5px}.layui-m-layerbtn span:active{background-color:#F6F6F6}.layui-m-layerend{position:absolute;right:7px;top:10px;width:30px;height:30px;border:0;font-weight:400;background:0 0;cursor:pointer;-webkit-appearance:none;font-size:30px}.layui-m-layerend::after,.layui-m-layerend::before{position:absolute;left:5px;top:15px;content:'';width:18px;height:1px;background-color:#999;transform:rotate(45deg);-webkit-transform:rotate(45deg);border-radius:3px}.layui-m-layerend::after{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}body .layui-m-layer .layui-m-layer-footer{position:fixed;width:95%;max-width:100%;margin:0 auto;left:0;right:0;bottom:10px;background:0 0}.layui-m-layer-footer .layui-m-layercont{padding:20px;border-radius:5px 5px 0 0;background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn{display:block;height:auto;background:0 0;border-top:none}.layui-m-layer-footer .layui-m-layerbtn span{background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn span[no]{color:#FD482C;border-top:1px solid #c2c2c2;border-radius:0 0 5px 5px}.layui-m-layer-footer .layui-m-layerbtn span[yes]{margin-top:10px;border-radius:5px}body .layui-m-layer .layui-m-layer-msg{width:auto;max-width:90%;margin:0 auto;bottom:-150px;background-color:rgba(0,0,0,.7);color:#fff}.layui-m-layer-msg .layui-m-layercont{padding:10px 20px} -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/plugns/layer/skin/default/icon-ext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/music/plugns/layer/skin/default/icon-ext.png -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/plugns/layer/skin/default/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/music/plugns/layer/skin/default/icon.png -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/plugns/layer/skin/default/loading-0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/music/plugns/layer/skin/default/loading-0.gif -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/plugns/layer/skin/default/loading-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/music/plugns/layer/skin/default/loading-1.gif -------------------------------------------------------------------------------- /homeassistant/.homeassistant/www/music/plugns/layer/skin/default/loading-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/homeassistant/.homeassistant/www/music/plugns/layer/skin/default/loading-2.gif -------------------------------------------------------------------------------- /homeassistant/install.sh: -------------------------------------------------------------------------------- 1 | #https://github.com/home-assistant/home-assistant 2 | #https://home-assistant.cc/installation/general/ 3 | 4 | #Home Assistant 官方推荐使用 Python 虚拟环境安装 Home Assistant 以避免影响生产环境。 5 | basepath=$(cd `dirname $0`; pwd) 6 | ln -s $basepath/.homeassistant ~/.homeassistant #复åé…çæ–‡ä 7 | 8 | cd ~/ 9 | sudo apt-get install python3 python3-venv python3-pip 10 | python3 -m venv homeassistant 11 | cd homeassistant 12 | source bin/activate 13 | python3 -m pip install homeassistant==0.83.3 14 | hass --open-ui 15 | 16 | sudo apt-get install vlc-nox 17 | sudo usermod -a -G audio pi 18 | 19 | 20 | # 以下代码可以放到开机自启动shell脚本中 21 | #killall hass 22 | nohup /home/pi/homeassistant/bin/hass -c "/home/pi/.homeassistant" >> /dev/null & 23 | -------------------------------------------------------------------------------- /init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "===init===" 3 | function update() 4 | { 5 | sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak 6 | sudo cp sources.list /etc/apt/sources.list 7 | sudo apt-get -y update 8 | sudo apt-get -y upgrade 9 | sudo apt-get -y dist-upgrade 10 | sudo rpi-update 11 | 12 | #配置wifi: 13 | sudo raspi-config 14 | #修改root密码: 15 | chpasswd root 16 | } 17 | 18 | function startup(){ 19 | #设置开机启动 20 | echo "add startup to /etc/rc.local demo:" 21 | cp ./startup/startup.sh /home/pi/ 22 | sudo cp /etc/rc.local /etc/rc.local.bak 23 | sudo cp ./startup/rc.local /etc/rc.local 24 | #cat ./rc.local 25 | #sudo vi /etc/rc.local 26 | } 27 | 28 | function base() 29 | { 30 | # vi 31 | sudo apt-get -y remove vim-common 32 | sudo apt-get -y install vim 33 | cp vimrc ~/.vimrc 34 | # IP 35 | #sudo cp interfaces /etc/network/interfaces 36 | #sudo systemctl daemon-reload 37 | #sudo service networking restart 38 | # Chinese 39 | #sudo apt-get -y install ttf-wqy-zenhei ttf-wqy-microhei 40 | #sudo apt-get -y install fcitx fcitx-googlepinyin fcitx-module-cloudpinyin fcitx-sunpinyin 41 | 42 | #echo LC_ALL="en_US.UTF-8" | sudo tee -a /etc/environment 43 | #echo LANG="en_US.UTF-8" | sudo tee -a /etc/environment 44 | # USB 45 | #echo "# USB Voltage" | sudo tee -a /boot/config.txt 46 | #echo "max_usb_current=1" | sudo tee -a /boot/config.txt 47 | # SSH 48 | #设置 SSH,打开密钥登录功能 49 | ssh-keygen -t rsa 50 | cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys 51 | echo "RSAAuthentication yes" | sudo tee -a /etc/ssh/sshd_config 52 | echo "PubkeyAuthentication yes" | sudo tee -a /etc/ssh/sshd_config 53 | echo "PermitRootLogin yes" | sudo tee -a /etc/ssh/sshd_config 54 | sudo /etc/init.d/ssh restart 55 | # 以后新电脑上先ssh-keygen 然后 将id_rsa.pub内容追加到服务器~/.ssh/authorized_keys中 56 | #echo "公钥内容" >> ~/.ssh/authorized_keys 57 | 58 | # zip 59 | sudo apt-get -y install zip 60 | # ssh key 61 | ssh-keygen -t rsa -C "764724624@qq.com" -b 4096 62 | 63 | 64 | 65 | } 66 | 67 | 68 | function dev() 69 | { 70 | #zsh 71 | #安装zsh: `sudo apt-get install zsh` 72 | sudo apt-get install zsh 73 | #安装oh-my-zsh: `sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"` 74 | sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)" 75 | cp ./zsh/.zshrc ~ #配置 76 | source ~/.zshrc 77 | #安装autojump: 78 | sudo apt-get install autojump 79 | 80 | sudo apt-get install git 81 | sudo apt-get install nodejs 82 | sudo apt-get install npm 83 | sudo apt-get install forever 84 | sudo ln -s /usr/bin/nodejs /usr/bin/node 85 | } 86 | 87 | function php_nginx_kode(){ 88 | echo "安装php nginx kode" 89 | return 90 | sudo -s 91 | apt-get install php7.0 php7.0-fpm php7.0-common php-mbstring 92 | apt-get remove --purge apache* -y 93 | apt-get autoremove --purge -y 94 | apt-get install nginx 95 | cp ./php_nginx_kode/default /etc/nginx/sites-available/ 96 | /etc/init.d/php7-fpm restart 97 | /etc/init.d/nginx restart 98 | wget http://static.kodcloud.com/update/download/kodexplorer4.25.zip 99 | unzip kodexplorer4.25.zip -d /home/pi/www/ 100 | su -c 'setenforce 0' 101 | chmod -R 777 /home/pi/www/ 102 | exit 103 | 104 | } 105 | 106 | function frpc(){ 107 | cp -r ./frpc/frpc /home/pi/bin/ 108 | cp ./frpc/frpc.ini /home/pi/ 109 | killall frpc 110 | nohup /home/pi/bin/frpc -c /home/pi/frpc.ini & 111 | } 112 | 113 | function tools(){ 114 | 115 | php_nginx_kode 116 | 117 | frpc 118 | return 119 | 120 | #安装aria2 121 | sudo apt-get install aria2 122 | cp -r ./aria2 /home/pi/ 123 | aria2c --conf-path="/home/pi/aria2/aria2.conf" -D 124 | 125 | # Samba 126 | cp ./samba/smb.conf /etc/samba/ 127 | cat ./samba/smb.conf 128 | sudo /etc/init.d/samba restart 129 | } 130 | #------------main 131 | update 132 | startup 133 | base 134 | dev 135 | tools 136 | 137 | # Done 138 | echo "===============end=================!" 139 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!bin/sh 2 | ./init.sh 3 | 4 | #更新源: 5 | # sudo -s 6 | # echo -e "deb http://mirrors.ustc.edu.cn/raspbian/raspbian/ stretch main contrib non-free rpi \n deb-src http://mirrors.ustc.edu.cn/raspbian/raspbian/ stretch main contrib non-free rpi" > /etc/apt/sources.list 7 | # echo -e "deb http://mirrors.ustc.edu.cn/archive.raspberrypi.org/ stretch main ui" > /etc/apt/sources.list.d/raspi.list 8 | # exit 9 | 10 | 11 | 12 | #重启网络: 13 | #sudo /etc/init.d/networking restar 14 | #端口查看: 15 | #netstat -tunlp -------------------------------------------------------------------------------- /kodi/install.sh: -------------------------------------------------------------------------------- 1 | 2 | #安装 3 | sudo apt-get update 4 | sudo apt-get upgrade 5 | sudo apt-get install kodi 6 | 7 | # 开机随桌面自启动 8 | cp ./kodi.desktop ~/.config/autostart/ 9 | 10 | # 汉化 参考https://jingyan.baidu.com/article/6dad50750da52ca122e36e5c.html 11 | # 插件 12 | # http://115.28.210.133/kodi/ 13 | # http://www.kodiplayer.cn/plugins/2835.html 14 | # 插件安装:https://app.yinxiang.com/shard/s1/nl/266062/e64d08a4-43c1-476d-a4f3-dea4634f813e 15 | 16 | -------------------------------------------------------------------------------- /kodi/kodi.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Exec=kodi -------------------------------------------------------------------------------- /kodi/readme.md: -------------------------------------------------------------------------------- 1 | # 插件库列表 2 | - repository.xbmcadult 3 | - repository.xbmc-addons-chinese 4 | - adulthideout: https://github.com/Vashiel/repository.adulthideout 5 | - Ultimate White Cream (plugin.video.uwc-1.1.63.zip) 6 | - A Japanese Adult Video scraper for XBMC:https://github.com/laoyang945/javscraper 7 | 8 | 备份打包:链接: https://pan.baidu.com/s/1H00V1QQwWzzJg9Lj-PPM2w 提取码: eacr 复制这段内容后打开百度网盘手机App,操作更方便哦 -------------------------------------------------------------------------------- /kodi/插件库/plugin.video.115_2.1.5.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/kodi/插件库/plugin.video.115_2.1.5.zip -------------------------------------------------------------------------------- /kodi/插件库/plugin.video.uwc-1.1.63.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/kodi/插件库/plugin.video.uwc-1.1.63.zip -------------------------------------------------------------------------------- /kodi/插件库/plugin.video.youporngay-0.3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/kodi/插件库/plugin.video.youporngay-0.3.zip -------------------------------------------------------------------------------- /kodi/插件库/repository.adulthideout-1.0.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/kodi/插件库/repository.adulthideout-1.0.1.zip -------------------------------------------------------------------------------- /kodi/插件库/repository.colossus-999.999.9.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/kodi/插件库/repository.colossus-999.999.9.zip -------------------------------------------------------------------------------- /kodi/插件库/repository.hdpfans.xbmc-addons-chinese.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/kodi/插件库/repository.hdpfans.xbmc-addons-chinese.zip -------------------------------------------------------------------------------- /kodi/插件库/repository.xbmc-addons-chinese-1.2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/kodi/插件库/repository.xbmc-addons-chinese-1.2.1.zip -------------------------------------------------------------------------------- /kodi/插件库/repository.xbmcadult-1.0.7.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/kodi/插件库/repository.xbmcadult-1.0.7.zip -------------------------------------------------------------------------------- /kodi/插件库/resource.language.zh_cn-1.0.3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/kodi/插件库/resource.language.zh_cn-1.0.3.zip -------------------------------------------------------------------------------- /kodi/插件库/script.module.beautifulsoup-3.2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/kodi/插件库/script.module.beautifulsoup-3.2.1.zip -------------------------------------------------------------------------------- /musicbox/autoplay.sh: -------------------------------------------------------------------------------- 1 | su - pi -c "tmux new-session -d -s musicbox musicbox -c '?'" 2 | -------------------------------------------------------------------------------- /musicbox/install.sh: -------------------------------------------------------------------------------- 1 | #参考:http://jingyan.eeboard.com/article/75227 2 | sudo apt-get install python-pip python-setuptools -y 3 | sudo pip install requests 4 | sudo pip2 install NetEase-MusicBox 5 | sudo apt-get install mpg123 6 | exit 7 | # 个人版安装 8 | #https://github.com/cloudswave/musicbox 9 | git clone git@github.com:cloudswave/musicbox.git && cd musicbox 10 | python setup.py install -------------------------------------------------------------------------------- /node_web/app.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | var express = require('express'); 3 | var app = express(); 4 | var child_process = require('child_process'); 5 | var spawnObj = null; 6 | var current_status = "stop"; 7 | app.get('/', function(req, res) { 8 | res.send('Hello World node11!'); 9 | }); 10 | app.get('/music/:status/:url', function(req, res) { 11 | res.send('music: ' + req.params.status + ':' + req.params.url); 12 | let status = req.params.status; 13 | let url = decodeURIComponent(req.params.url); 14 | if (!spawnObj) { 15 | spawnObj = child_process.spawn('mpg123', ['-R'], { 16 | encoding: 'utf-8' 17 | }); 18 | spawnObj.stdout.on('data', function(chunk) { 19 | console.log(chunk.toString()); 20 | }); 21 | spawnObj.stderr.on('data', (data) => { 22 | console.log(data); 23 | }); 24 | spawnObj.on('close', function(code) { 25 | console.log('close code : ' + code); 26 | }); 27 | spawnObj.on('exit', (code) => { 28 | console.log('exit code : ' + code); 29 | }); 30 | spawnObj.stdin.write('V 60\n'); 31 | } 32 | try { 33 | 34 | switch (status) { 35 | case 'play': 36 | spawnObj.stdin.write(`L ${url}\n`); 37 | break; 38 | case 'stop': 39 | if(spawnObj) { 40 | spawnObj.stdin.write('Q\n'); 41 | spawnObj.kill(); 42 | spawnObj = null; 43 | } 44 | 45 | break; 46 | case 'pause': 47 | if(spawnObj) { 48 | spawnObj.stdin.write('P\n'); 49 | } 50 | break; 51 | case 'resume': 52 | if(spawnObj) 53 | spawnObj.stdin.write('P\n'); 54 | default: 55 | // code 56 | } 57 | current_status = status; 58 | } catch (e) { 59 | console.error('error:',e); 60 | } 61 | 62 | }); 63 | app.get('/frpc', function(req, res) { 64 | // child_process.exec('/bin/sh /home/pi/pi3-script/node_web/shell/frpc.sh',null,function (err, stdout, stderr) { 65 | // console.log('frpc sh ./shell/frpc.sh!',err,stdout.stderr); 66 | // }); 67 | res.send('frpc success!'); 68 | }); 69 | var server = app.listen(3000, function() { 70 | var host = server.address().address; 71 | var port = server.address().port; 72 | console.log('Example app listening at http://%s:%s', host, port); 73 | }); -------------------------------------------------------------------------------- /node_web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-web", 3 | "version": "0.0.0", 4 | "description": "a base node express webserver", 5 | "main": "index.js", 6 | "dependencies": { 7 | "express": "^4.16.3" 8 | }, 9 | "devDependencies": {}, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "ethanzhu.zxb@gmail.com", 14 | "license": "ISC" 15 | } 16 | -------------------------------------------------------------------------------- /node_web/shell/frpc.sh: -------------------------------------------------------------------------------- 1 | killall frpc 2 | nohup /home/pi/bin/frpc -c /home/pi/frpc.ini & 3 | echo `date`:frpc >> /home/pi/pi3-script/node_web/shell/shell.log -------------------------------------------------------------------------------- /node_web/shell/play.sh: -------------------------------------------------------------------------------- 1 | echo `pwd` >> /home/pi/tmp.log 2 | killall mpg123 3 | nohup mpg123 http://dl.stream.qqmusic.qq.com/M800003LqdzX0edhb9.mp3\?vkey\=86A608E8E95C6BC8E99FA203929DA5DCB319FE9BF55FD49FA11422952DD01EB67FE26E676BA776AA87BF83803410A9D41B4045CF67C2957B\&guid\=5150825362\&fromtag\=1 >> /dev/null & -------------------------------------------------------------------------------- /npc/conf/multi_account.conf: -------------------------------------------------------------------------------- 1 | # key -> user | value -> pwd 2 | npc=npc.pwd -------------------------------------------------------------------------------- /npc/conf/npc.conf: -------------------------------------------------------------------------------- 1 | [common] 2 | server_addr=127.0.0.1:8024 3 | conn_type=tcp 4 | vkey=123 5 | auto_reconnection=true 6 | max_conn=1000 7 | flow_limit=1000 8 | rate_limit=1000 9 | basic_username=11 10 | basic_password=3 11 | web_username=user 12 | web_password=1234 13 | crypt=true 14 | compress=true 15 | #pprof_addr=0.0.0.0:9999 16 | disconnect_timeout=60 17 | 18 | [health_check_test1] 19 | health_check_timeout=1 20 | health_check_max_failed=3 21 | health_check_interval=1 22 | health_http_url=/ 23 | health_check_type=http 24 | health_check_target=127.0.0.1:8083,127.0.0.1:8082 25 | 26 | [health_check_test2] 27 | health_check_timeout=1 28 | health_check_max_failed=3 29 | health_check_interval=1 30 | health_check_type=tcp 31 | health_check_target=127.0.0.1:8083,127.0.0.1:8082 32 | 33 | [web] 34 | host=c.o.com 35 | target_addr=127.0.0.1:8083,127.0.0.1:8082 36 | 37 | [tcp] 38 | mode=tcp 39 | target_addr=127.0.0.1:8080 40 | server_port=10000 41 | 42 | [socks5] 43 | mode=socks5 44 | server_port=19009 45 | multi_account=multi_account.conf 46 | 47 | [file] 48 | mode=file 49 | server_port=19008 50 | local_path=/Users/liuhe/Downloads 51 | strip_pre=/web/ 52 | 53 | [http] 54 | mode=httpProxy 55 | server_port=19004 56 | 57 | [udp] 58 | mode=udp 59 | server_port=12253 60 | target_addr=114.114.114.114:53 61 | 62 | [ssh_secret] 63 | mode=secret 64 | password=ssh2 65 | target_addr=123.206.77.88:22 66 | 67 | [ssh_p2p] 68 | mode=p2p 69 | password=ssh3 70 | 71 | [secret_ssh] 72 | local_port=2001 73 | password=ssh2 74 | 75 | [p2p_ssh] 76 | local_port=2002 77 | password=ssh3 78 | target_addr=123.206.77.88:22 -------------------------------------------------------------------------------- /npc/install.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/npc/install.sh -------------------------------------------------------------------------------- /npc/npc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudswave/pi3-script/8bca339f18fe9e7f8796ed434abc495c60cc94fa/npc/npc -------------------------------------------------------------------------------- /overlayfs/.bashrc: -------------------------------------------------------------------------------- 1 | # ~/.bashrc: executed by bash(1) for non-login shells. 2 | # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) 3 | # for examples 4 | 5 | # If not running interactively, don't do anything 6 | case $- in 7 | *i*) ;; 8 | *) return;; 9 | esac 10 | 11 | # don't put duplicate lines or lines starting with space in the history. 12 | # See bash(1) for more options 13 | HISTCONTROL=ignoreboth 14 | 15 | # append to the history file, don't overwrite it 16 | shopt -s histappend 17 | 18 | # for setting history length see HISTSIZE and HISTFILESIZE in bash(1) 19 | HISTSIZE=1000 20 | HISTFILESIZE=2000 21 | 22 | # check the window size after each command and, if necessary, 23 | # update the values of LINES and COLUMNS. 24 | shopt -s checkwinsize 25 | 26 | # If set, the pattern "**" used in a pathname expansion context will 27 | # match all files and zero or more directories and subdirectories. 28 | #shopt -s globstar 29 | 30 | # make less more friendly for non-text input files, see lesspipe(1) 31 | #[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" 32 | 33 | # set variable identifying the chroot you work in (used in the prompt below) 34 | if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then 35 | debian_chroot=$(cat /etc/debian_chroot) 36 | fi 37 | 38 | # set a fancy prompt (non-color, unless we know we "want" color) 39 | case "$TERM" in 40 | xterm-color|*-256color) color_prompt=yes;; 41 | esac 42 | 43 | # uncomment for a colored prompt, if the terminal has the capability; turned 44 | # off by default to not distract the user: the focus in a terminal window 45 | # should be on the output of commands, not on the prompt 46 | #force_color_prompt=yes 47 | 48 | if [ -n "$force_color_prompt" ]; then 49 | if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then 50 | # We have color support; assume it's compliant with Ecma-48 51 | # (ISO/IEC-6429). (Lack of such support is extremely rare, and such 52 | # a case would tend to support setf rather than setaf.) 53 | color_prompt=yes 54 | else 55 | color_prompt= 56 | fi 57 | fi 58 | 59 | if [ "$color_prompt" = yes ]; then 60 | PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' 61 | else 62 | PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' 63 | fi 64 | unset color_prompt force_color_prompt 65 | 66 | # If this is an xterm set the title to user@host:dir 67 | case "$TERM" in 68 | xterm*|rxvt*) 69 | PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" 70 | ;; 71 | *) 72 | ;; 73 | esac 74 | 75 | # enable color support of ls and also add handy aliases 76 | if [ -x /usr/bin/dircolors ]; then 77 | test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" 78 | alias ls='ls --color=auto' 79 | #alias dir='dir --color=auto' 80 | #alias vdir='vdir --color=auto' 81 | 82 | #alias grep='grep --color=auto' 83 | #alias fgrep='fgrep --color=auto' 84 | #alias egrep='egrep --color=auto' 85 | fi 86 | 87 | # colored GCC warnings and errors 88 | #export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' 89 | 90 | # some more ls aliases 91 | #alias ll='ls -l' 92 | #alias la='ls -A' 93 | #alias l='ls -CF' 94 | 95 | # Alias definitions. 96 | # You may want to put all your additions into a separate file like 97 | # ~/.bash_aliases, instead of adding them here directly. 98 | # See /usr/share/doc/bash-doc/examples in the bash-doc package. 99 | 100 | if [ -f ~/.bash_aliases ]; then 101 | . ~/.bash_aliases 102 | fi 103 | 104 | # enable programmable completion features (you don't need to enable 105 | # this, if it's already enabled in /etc/bash.bashrc and /etc/profile 106 | # sources /etc/bash.bashrc). 107 | if ! shopt -oq posix; then 108 | if [ -f /usr/share/bash-completion/bash_completion ]; then 109 | . /usr/share/bash-completion/bash_completion 110 | elif [ -f /etc/bash_completion ]; then 111 | . /etc/bash_completion 112 | fi 113 | fi 114 | 115 | function reboot_rw(){ 116 | sudo mount -o remount,rw /boot 117 | sudo sed -i 's/ init=\/sbin\/overlayRoot.sh//g' /boot/cmdline.txt 118 | sudo reboot 119 | } 120 | function reboot_ro() { 121 | sudo mount -o remount,rw /boot 122 | sudo sed -i 's/\($\)/ init=\/sbin\/overlayRoot.sh/g' /boot/cmdline.txt 123 | sudo reboot 124 | } 125 | function rw() { 126 | sudo mount -o remount,rw /ro 127 | sudo mount -o remount,rw /boot 128 | } 129 | -------------------------------------------------------------------------------- /overlayfs/overlayRoot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Read-only Root-FS for Raspian using overlayfs 3 | # Version 1.1 4 | # 5 | # Version History: 6 | # 1.0: initial release 7 | # 1.1: adopted new fstab style with PARTUUID. the script will now look for a /dev/xyz definiton first 8 | # (old raspbian), if that is not found, it will look for a partition with LABEL=rootfs, if that 9 | # is not found it look for a PARTUUID string in fstab for / and convert that to a device name 10 | # using the blkid command. 11 | # 12 | # Created 2017 by Pascal Suter @ DALCO AG, Switzerland to work on Raspian as custom init script 13 | # (raspbian does not use an initramfs on boot) 14 | # 15 | # This program is free software: you can redistribute it and/or modify 16 | # it under the terms of the GNU General Public License as published by 17 | # the Free Software Foundation, either version 3 of the License, or 18 | # (at your option) any later version. 19 | # 20 | # This program is distributed in the hope that it will be useful, 21 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | # GNU General Public License for more details. 24 | # 25 | # You should have received a copy of the GNU General Public License 26 | # along with this program. If not, see 27 | # . 28 | # 29 | # 30 | # Tested with Raspbian mini, 2018-10-09 31 | # 32 | # This script will mount the root filesystem read-only and overlay it with a temporary tempfs 33 | # which is read-write mounted. This is done using the overlayFS which is part of the linux kernel 34 | # since version 3.18. 35 | # when this script is in use, all changes made to anywhere in the root filesystem mount will be lost 36 | # upon reboot of the system. The SD card will only be accessed as read-only drive, which significantly 37 | # helps to prolong its life and prevent filesystem coruption in environments where the system is usually 38 | # not shut down properly 39 | # 40 | # Install: 41 | # copy this script to /sbin/overlayRoot.sh, make it executable and add "init=/sbin/overlayRoot.sh" to the 42 | # cmdline.txt file in the raspbian image's boot partition. 43 | # I strongly recommend to disable swapping before using this. it will work with swap but that just does 44 | # not make sens as the swap file will be stored in the tempfs which again resides in the ram. 45 | # run these commands on the booted raspberry pi BEFORE you set the init=/sbin/overlayRoot.sh boot option: 46 | # sudo dphys-swapfile swapoff 47 | # sudo dphys-swapfile uninstall 48 | # sudo update-rc.d dphys-swapfile remove 49 | # 50 | # To install software, run upgrades and do other changes to the raspberry setup, simply remove the init= 51 | # entry from the cmdline.txt file and reboot, make the changes, add the init= entry and reboot once more. 52 | 53 | fail(){ 54 | echo -e "$1" 55 | /bin/bash 56 | } 57 | 58 | # load module 59 | modprobe overlay 60 | if [ $? -ne 0 ]; then 61 | fail "ERROR: missing overlay kernel module" 62 | fi 63 | # mount /proc 64 | mount -t proc proc /proc 65 | if [ $? -ne 0 ]; then 66 | fail "ERROR: could not mount proc" 67 | fi 68 | # create a writable fs to then create our mountpoints 69 | mount -t tmpfs inittemp /mnt 70 | if [ $? -ne 0 ]; then 71 | fail "ERROR: could not create a temporary filesystem to mount the base filesystems for overlayfs" 72 | fi 73 | mkdir /mnt/lower 74 | mkdir /mnt/rw 75 | mount -t tmpfs root-rw /mnt/rw 76 | if [ $? -ne 0 ]; then 77 | fail "ERROR: could not create tempfs for upper filesystem" 78 | fi 79 | mkdir /mnt/rw/upper 80 | mkdir /mnt/rw/work 81 | mkdir /mnt/newroot 82 | # mount root filesystem readonly 83 | rootDev=`awk '$2 == "/" {print $1}' /etc/fstab` 84 | rootMountOpt=`awk '$2 == "/" {print $4}' /etc/fstab` 85 | rootFsType=`awk '$2 == "/" {print $3}' /etc/fstab` 86 | echo "check if we can locate the root device based on fstab" 87 | blkid $rootDev 88 | if [ $? -gt 0 ]; then 89 | echo "no success, try if a filesystem with label 'rootfs' is avaialble" 90 | rootDevFstab=$rootDev 91 | rootDev=`blkid -L "rootfs"` 92 | if [ $? -gt 0 ]; then 93 | echo "no luck either, try to further parse fstab's root device definition" 94 | echo "try if fstab contains a PARTUUID definition" 95 | echo "$rootDevFstab" | grep 'PARTUUID=\(.*\)-\([0-9]\{2\}\)' 96 | if [ $? -gt 0 ]; then 97 | fail "could not find a root filesystem device in fstab. Make sure that fstab contains a device definition or a PARTUUID entry for / or that the root filesystem has a label 'rootfs' assigned to it" 98 | fi 99 | device="" 100 | partition="" 101 | eval `echo "$rootDevFstab" | sed -e 's/PARTUUID=\(.*\)-\([0-9]\{2\}\)/device=\1;partition=\2/'` 102 | rootDev=`blkid -t "PTUUID=$device" | awk -F : '{print $1}'`p$(($partition)) 103 | blkid $rootDev 104 | if [ $? -gt 0 ]; then 105 | fail "The PARTUUID entry in fstab could not be converted into a valid device name. Make sure that fstab contains a device definition or a PARTUUID entry for / or that the root filesystem has a label 'rootfs' assigned to it" 106 | fi 107 | fi 108 | fi 109 | mount -t ${rootFsType} -o ${rootMountOpt},ro ${rootDev} /mnt/lower 110 | if [ $? -ne 0 ]; then 111 | fail "ERROR: could not ro-mount original root partition" 112 | fi 113 | mount -t overlay -o lowerdir=/mnt/lower,upperdir=/mnt/rw/upper,workdir=/mnt/rw/work overlayfs-root /mnt/newroot 114 | if [ $? -ne 0 ]; then 115 | fail "ERROR: could not mount overlayFS" 116 | fi 117 | # create mountpoints inside the new root filesystem-overlay 118 | mkdir /mnt/newroot/ro 119 | mkdir /mnt/newroot/rw 120 | # remove root mount from fstab (this is already a non-permanent modification) 121 | grep -v "$rootDev" /mnt/lower/etc/fstab > /mnt/newroot/etc/fstab 122 | echo "#the original root mount has been removed by overlayRoot.sh" >> /mnt/newroot/etc/fstab 123 | echo "#this is only a temporary modification, the original fstab" >> /mnt/newroot/etc/fstab 124 | echo "#stored on the disk can be found in /ro/etc/fstab" >> /mnt/newroot/etc/fstab 125 | # change to the new overlay root 126 | cd /mnt/newroot 127 | pivot_root . mnt 128 | exec chroot . sh -c "$(cat <> ${ERROR_LOG_FILE} 4 | rclone copy /media/pi/DA18-EBFA/pi-backup/ remote:pi 5 | rclone copy /media/pi/DA18-EBFA/apk/ remote:apk 6 | rclone copy /media/pi/DA18-EBFA/ip-webcam/ remote:ip-webcam 7 | rclone copy /media/pi/DA18-EBFA/pc-software/ remote:ip-software 8 | rclone copy /media/pi/DA18-EBFA/document/ remote:document 9 | rclone copy /media/pi/DA18-EBFA/fuli/short-video/ remote:fuli/short-video 10 | echo $(date "+%Y-%m-%d %H:%M:%S"): "onedrive backup data end" >> ${ERROR_LOG_FILE} 11 | -------------------------------------------------------------------------------- /rclone/readme.md: -------------------------------------------------------------------------------- 1 | 安装参考:https://www.jianshu.com/p/56eb8ed333ac -------------------------------------------------------------------------------- /samba/install.sh: -------------------------------------------------------------------------------- 1 | # 参考:https://www.cnblogs.com/mnstar/p/8144943.html 2 | sudo cp -rf ./smb.conf /etc/samba/ 3 | # 设置pi密码 4 | echo "please set smbpasswd for pi" 5 | sudo smbpasswd -a pi 6 | 7 | sudo /etc/init.d/samba restart 8 | -------------------------------------------------------------------------------- /samba/smb.conf: -------------------------------------------------------------------------------- 1 | # 2 | # Sample configuration file for the Samba suite for Debian GNU/Linux. 3 | # 4 | # 5 | # This is the main Samba configuration file. You should read the 6 | # smb.conf(5) manual page in order to understand the options listed 7 | # here. Samba has a huge number of configurable options most of which 8 | # are not shown in this example 9 | # 10 | # Some options that are often worth tuning have been included as 11 | # commented-out examples in this file. 12 | # - When such options are commented with ";", the proposed setting 13 | # differs from the default Samba behaviour 14 | # - When commented with "#", the proposed setting is the default 15 | # behaviour of Samba but the option is considered important 16 | # enough to be mentioned here 17 | # 18 | # NOTE: Whenever you modify this file you should run the command 19 | # "testparm" to check that you have not made any basic syntactic 20 | # errors. 21 | 22 | #======================= Global Settings ======================= 23 | 24 | [global] 25 | 26 | ## Browsing/Identification ### 27 | 28 | # Change this to the workgroup/NT-domain name your Samba server will part of 29 | workgroup = WORKGROUP 30 | 31 | # Windows Internet Name Serving Support Section: 32 | # WINS Support - Tells the NMBD component of Samba to enable its WINS Server 33 | # wins support = no 34 | 35 | # WINS Server - Tells the NMBD components of Samba to be a WINS Client 36 | # Note: Samba can be either a WINS Server, or a WINS Client, but NOT both 37 | ; wins server = w.x.y.z 38 | 39 | # This will prevent nmbd to search for NetBIOS names through DNS. 40 | dns proxy = no 41 | 42 | #### Networking #### 43 | 44 | # The specific set of interfaces / networks to bind to 45 | # This can be either the interface name or an IP address/netmask; 46 | # interface names are normally preferred 47 | ; interfaces = 127.0.0.0/8 eth0 48 | 49 | # Only bind to the named interfaces and/or networks; you must use the 50 | # 'interfaces' option above to use this. 51 | # It is recommended that you enable this feature if your Samba machine is 52 | # not protected by a firewall or is a firewall itself. However, this 53 | # option cannot handle dynamic or non-broadcast interfaces correctly. 54 | ; bind interfaces only = yes 55 | 56 | 57 | 58 | #### Debugging/Accounting #### 59 | 60 | # This tells Samba to use a separate log file for each machine 61 | # that connects 62 | log file = /var/log/samba/log.%m 63 | 64 | # Cap the size of the individual log files (in KiB). 65 | max log size = 1000 66 | 67 | # If you want Samba to only log through syslog then set the following 68 | # parameter to 'yes'. 69 | # syslog only = no 70 | 71 | # We want Samba to log a minimum amount of information to syslog. Everything 72 | # should go to /var/log/samba/log.{smbd,nmbd} instead. If you want to log 73 | # through syslog you should set the following parameter to something higher. 74 | syslog = 0 75 | 76 | # Do something sensible when Samba crashes: mail the admin a backtrace 77 | panic action = /usr/share/samba/panic-action %d 78 | 79 | 80 | ####### Authentication ####### 81 | 82 | # Server role. Defines in which mode Samba will operate. Possible 83 | # values are "standalone server", "member server", "classic primary 84 | # domain controller", "classic backup domain controller", "active 85 | # directory domain controller". 86 | # 87 | # Most people will want "standalone sever" or "member server". 88 | # Running as "active directory domain controller" will require first 89 | # running "samba-tool domain provision" to wipe databases and create a 90 | # new domain. 91 | server role = standalone server 92 | 93 | # If you are using encrypted passwords, Samba will need to know what 94 | # password database type you are using. 95 | passdb backend = tdbsam 96 | 97 | obey pam restrictions = yes 98 | 99 | # This boolean parameter controls whether Samba attempts to sync the Unix 100 | # password with the SMB password when the encrypted SMB password in the 101 | # passdb is changed. 102 | unix password sync = yes 103 | 104 | # For Unix password sync to work on a Debian GNU/Linux system, the following 105 | # parameters must be set (thanks to Ian Kahan < for 106 | # sending the correct chat script for the passwd program in Debian Sarge). 107 | passwd program = /usr/bin/passwd %u 108 | passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* . 109 | 110 | # This boolean controls whether PAM will be used for password changes 111 | # when requested by an SMB client instead of the program listed in 112 | # 'passwd program'. The default is 'no'. 113 | pam password change = yes 114 | 115 | # This option controls how unsuccessful authentication attempts are mapped 116 | # to anonymous connections 117 | map to guest = bad user 118 | 119 | ########## Domains ########### 120 | 121 | # 122 | # The following settings only takes effect if 'server role = primary 123 | # classic domain controller', 'server role = backup domain controller' 124 | # or 'domain logons' is set 125 | # 126 | 127 | # It specifies the location of the user's 128 | # profile directory from the client point of view) The following 129 | # required a [profiles] share to be setup on the samba server (see 130 | # below) 131 | ; logon path = \\%N\profiles\%U 132 | # Another common choice is storing the profile in the user's home directory 133 | # (this is Samba's default) 134 | # logon path = \\%N\%U\profile 135 | 136 | # The following setting only takes effect if 'domain logons' is set 137 | # It specifies the location of a user's home directory (from the client 138 | # point of view) 139 | ; logon drive = H: 140 | # logon home = \\%N\%U 141 | 142 | # The following setting only takes effect if 'domain logons' is set 143 | # It specifies the script to run during logon. The script must be stored 144 | # in the [netlogon] share 145 | # NOTE: Must be store in 'DOS' file format convention 146 | ; logon script = logon.cmd 147 | 148 | # This allows Unix users to be created on the domain controller via the SAMR 149 | # RPC pipe. The example command creates a user account with a disabled Unix 150 | # password; please adapt to your needs 151 | ; add user script = /usr/sbin/adduser --quiet --disabled-password --gecos "" %u 152 | 153 | # This allows machine accounts to be created on the domain controller via the 154 | # SAMR RPC pipe. 155 | # The following assumes a "machines" group exists on the system 156 | ; add machine script = /usr/sbin/useradd -g machines -c "%u machine account" -d /var/lib/samba -s /bin/false %u 157 | 158 | # This allows Unix groups to be created on the domain controller via the SAMR 159 | # RPC pipe. 160 | ; add group script = /usr/sbin/addgroup --force-badname %g 161 | 162 | ############ Misc ############ 163 | 164 | # Using the following line enables you to customise your configuration 165 | # on a per machine basis. The %m gets replaced with the netbios name 166 | # of the machine that is connecting 167 | ; include = /home/samba/etc/smb.conf.%m 168 | 169 | # Some defaults for winbind (make sure you're not using the ranges 170 | # for something else.) 171 | ; idmap uid = 10000-20000 172 | ; idmap gid = 10000-20000 173 | ; template shell = /bin/bash 174 | 175 | # Setup usershare options to enable non-root users to share folders 176 | # with the net usershare command. 177 | 178 | # Maximum number of usershare. 0 (default) means that usershare is disabled. 179 | ; usershare max shares = 100 180 | 181 | # Allow users who've been granted usershare privileges to create 182 | # public shares, not just authenticated ones 183 | usershare allow guests = yes 184 | 185 | #======================= Share Definitions ======================= 186 | 187 | [homes] 188 | comment = Home Directories 189 | browseable = no 190 | 191 | # By default, the home directories are exported read-only. Change the 192 | # next parameter to 'no' if you want to be able to write to them. 193 | read only = yes 194 | 195 | # File creation mask is set to 0700 for security reasons. If you want to 196 | # create files with group=rw permissions, set next parameter to 0775. 197 | create mask = 0700 198 | 199 | # Directory creation mask is set to 0700 for security reasons. If you want to 200 | # create dirs. with group=rw permissions, set next parameter to 0775. 201 | directory mask = 0700 202 | 203 | # By default, \\server\username shares can be connected to by anyone 204 | # with access to the samba server. 205 | # The following parameter makes sure that only "username" can connect 206 | # to \\server\username 207 | # This might need tweaking when using external authentication schemes 208 | valid users = %S 209 | 210 | # Un-comment the following and create the netlogon directory for Domain Logons 211 | # (you need to configure Samba to act as a domain controller too.) 212 | ;[netlogon] 213 | ; comment = Network Logon Service 214 | ; path = /home/samba/netlogon 215 | ; guest ok = yes 216 | ; read only = yes 217 | 218 | # Un-comment the following and create the profiles directory to store 219 | # users profiles (see the "logon path" option above) 220 | # (you need to configure Samba to act as a domain controller too.) 221 | # The path below should be writable by all users so that their 222 | # profile directory may be created the first time they log on 223 | ;[profiles] 224 | ; comment = Users profiles 225 | ; path = /home/samba/profiles 226 | ; guest ok = no 227 | ; browseable = no 228 | ; create mask = 0600 229 | ; directory mask = 0700 230 | 231 | [printers] 232 | comment = All Printers 233 | browseable = no 234 | path = /var/spool/samba 235 | printable = yes 236 | guest ok = no 237 | read only = yes 238 | create mask = 0700 239 | 240 | # Windows clients look for this share name as a source of downloadable 241 | # printer drivers 242 | [print$] 243 | comment = Printer Drivers 244 | path = /var/lib/samba/printers 245 | browseable = yes 246 | read only = yes 247 | guest ok = no 248 | # Uncomment to allow remote administration of Windows print drivers. 249 | # You may need to replace 'lpadmin' with the name of the group your 250 | # admin users are members of. 251 | # Please note that you also need to set appropriate Unix permissions 252 | # to the drivers directory for these users to have write rights in it 253 | ; write list = root, @lpadmin 254 | 255 | [pi] 256 | # 说明信息 257 | comment = NAS Storage 258 | # 可以访问的用户 259 | valid users = pi,root 260 | # 共享文件的路径,raspberry pi 会自动将连接到其上的外接存储设备挂载到/media/pi/目录下。 261 | path = /media/pi/ 262 | # 可被其他人看到资源名称(非内容) 263 | browseable = yes 264 | # 可写 265 | writable = yes 266 | # 新建文件的权限为 664 267 | create mask = 0664 268 | # 新建目录的权限为 775 269 | directory mask = 0775 270 | -------------------------------------------------------------------------------- /sources.list: -------------------------------------------------------------------------------- 1 | deb http://mirrors.ustc.edu.cn/raspbian/raspbian/ stretch main contrib non-free rpi 2 | deb-src http://mirrors.ustc.edu.cn/raspbian/raspbian/ stretch main contrib non-free rpi 3 | -------------------------------------------------------------------------------- /startup/init.d/my_boot: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # /etc/init.d/my_boot 3 | 4 | ### BEGIN INIT INFO 5 | # Provides: embbnux 6 | # Required-Start: $remote_fs $syslog 7 | # Required-Stop: $remote_fs $syslog 8 | # Default-Start: 2 3 4 5 9 | # Default-Stop: 0 1 6 10 | # Short-Description: my_boot initscript 11 | # Description: This service for my_boot 12 | ### END INIT INFO 13 | case "$1" in 14 | start): 15 | echo "Starting app" 16 | echo `date`:my boot start frpc >> /home/pi/boot.log 17 | killall frpc 18 | nohup /home/pi/bin/frpc -c /home/pi/frpc.ini >> /dev/null & 19 | ;; 20 | stop): 21 | echo "stop" 22 | killall frpc 23 | ;; 24 | *): 25 | echo "Usage: $0 (start|stop)" 26 | exit 1 27 | ;; 28 | esac 29 | 30 | exit 0 31 | -------------------------------------------------------------------------------- /startup/install.sh: -------------------------------------------------------------------------------- 1 | basepath=$(cd `dirname $0`; pwd) 2 | ln -s $basepath/startup190519.sh ~/startup.sh 3 | #cp ./startup.sh /home/pi 4 | echo "please add startup to /etc/rc.local demo:" 5 | cat ./rc.local 6 | sudo vi /etc/rc.local 7 | -------------------------------------------------------------------------------- /startup/rc.local: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # 3 | # rc.local 4 | # 5 | # This script is executed at the end of each multiuser runlevel. 6 | # Make sure that the script will "exit 0" on success or any other 7 | # value on error. 8 | # 9 | # In order to enable or disable this script just change the execution 10 | # bits. 11 | # 12 | # By default this script does nothing. 13 | 14 | # Print the IP address 15 | _IP=$(hostname -I) || true 16 | if [ "$_IP" ]; then 17 | printf "My IP address is %s\n" "$_IP" 18 | fi 19 | su pi -c "exec /home/pi/startup.sh" #以pi用户身份运行脚本 20 | exit 0 21 | -------------------------------------------------------------------------------- /startup/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd /home/pi 3 | # koe 4 | echo "kode start" >> ./startup.log 5 | /etc/init.d/php7-fpm restart & 6 | /etc/init.d/nginx restart & 7 | 8 | # node 9 | echo "node start" >> ./startup.log 10 | forever start -w ./pi3-script/node_web/app.js 11 | 12 | # nas 13 | echo samba restart >> ./startup.log 14 | /etc/init.d/samba restart & 15 | 16 | # frpc 17 | echo "frpc start" >> ./startup.log 18 | nohup ./bin/frpc & 19 | 20 | #挂载U 21 | ./mount-usb.sh 22 | 23 | #wifi助手 24 | echo "raspberry_pi_helper start" >> ./startup.log 25 | sudo nohup ./raspberry_pi_helper/start_pihelper.py & -------------------------------------------------------------------------------- /startup/startup190519.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | LOG_FILE="/home/pi/boot.log" 3 | logit(){ 4 | echo $(date "+%Y-%m-%d %H:%M:%S"): ${*} >> ${LOG_FILE} 5 | } 6 | cd /home/pi 7 | # koe 8 | logit "samba aria2c start" 9 | /etc/init.d/samba restart & 10 | #aria2c --conf-path="/home/pi/pi3-script/aria2/aria2.conf" -D & 11 | qbittorrent-nox --webui-port=8081 -d 12 | 13 | logit "homeassistan start" 14 | nohup /home/pi/homeassistant/bin/hass -c "/home/pi/.homeassistant" >> /dev/null & 15 | 16 | logit "webssh start" 17 | screen -dmS wssh ./bin/wssh 18 | 19 | # 监控frpc进程 20 | logit "frpc start" 21 | nohup ./bin/monitor.sh >> /dev/null & 22 | 23 | #syncthing 24 | logit "syncthing start" 25 | nohup ./bin/syncthing/syncthing >> /dev/null & 26 | 27 | logit "php nginx start" 28 | /etc/init.d/php7.0-fpm restart & 29 | /etc/init.d/nginx restart & 30 | sleep 5 31 | logit "chown -R pi:pi /run/php/" 32 | sudo chown -R pi:pi /run/php/ & 33 | -------------------------------------------------------------------------------- /startup/startup_181206.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | LOG_FILE="/home/pi/boot.log" 3 | function logit() 4 | { 5 | echo "[${USER}][`date`] - ${*}" >> ${LOG_FILE} 6 | } 7 | cd /home/pi 8 | 9 | # koe 10 | logit "kode start" 11 | /etc/init.d/php7.0-fpm restart & 12 | /etc/init.d/nginx restart & 13 | 14 | # node 15 | logit "node start" 16 | forever start -w ./pi3-script/node_web/app.js 17 | 18 | # nas 19 | logit "samba restart" 20 | /etc/init.d/samba restart & 21 | 22 | # web shell 23 | shellinaboxd -b -t -p 4200 24 | 25 | 26 | #wifi助手 27 | logit "raspberry_pi_helper start" 28 | sudo nohup ./raspberry_pi_helper/start_pihelper.py >> /dev/null & 29 | 30 | # 智能家居助手 31 | nohup ./homeassistant/bin/hass -c "/home/pi/.homeassistant" >> /dev/null & 32 | 33 | # 监控frpc进程 34 | #nohup ./monitor.sh >> /dev/null & 35 | 36 | # 叮当语音 37 | #echo ...启动叮当语音.. >> ./startup.log 38 | #sh /home/pi/dingdang/launcher/dingdang-launcher-user.sh 39 | # shairplay 40 | #nohup shairplay -a pi >> /dev/null & 41 | #logit "shairport start" 42 | #./shairport/shairport -a pi -d 43 | 44 | # frpc 45 | #logit "frpc start" 46 | #nohup ./bin/frpc >> /dev/null & 47 | 48 | # usb mount 49 | ./my_usb.sh 50 | 51 | #设置硬盘自动休眠,数值/12 = 分钟,设置为120就是无操作10分钟后休眠 52 | sudo hdparm -S 120 /dev/sda1 53 | 54 | # aria2c 55 | logit "aria2c start" 56 | aria2c --conf-path="/home/pi/aria2/aria2.conf" -D 57 | 58 | -------------------------------------------------------------------------------- /syncthing/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 参考https://www.jianshu.com/p/9e6289478bc8 3 | mkdir /home/pi/bin/ 4 | cd /home/pi/bin/ 5 | wget https://github.com/syncthing/syncthing/releases/download/v1.1.4-rc.1/syncthing-linux-arm-v1.1.4-rc.1.tar.gz 6 | tar zxvf syncthing-linux-arm-v1.1.4-rc.1.tar.gz 7 | rm -rf syncthing-linux-arm-v1.1.4-rc.1.tar.gz 8 | mv syncthing-linux-arm-v1.1.4-rc.1 syncthing 9 | chmod +x ./syncthing/syncthing 10 | ./syncthing/syncthing 11 | -------------------------------------------------------------------------------- /usbmount/my_usb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #sudo umount /home/pi/share/my_usb 3 | #sudo rm -rf /home/pi/share/my_usb 4 | #mkdir /home/pi/share/my_usb 5 | sudo mount /dev/sda1 /home/pi/share/my_usb -w 6 | -------------------------------------------------------------------------------- /usbmount/usb_mount.sh: -------------------------------------------------------------------------------- 1 | #安装所需软件包 2 | sudo apt-get install ntfs-3g 3 | #加载内核模块 4 | sudo modprobe fuse 5 | mkdir /home/pi/share/my_usb 6 | sudo mount /dev/sda1 /home/pi/share/my_usb -w 7 | #sudo umount /home/pi/share/my_usb 8 | sudo echo /dev/sda1 /home/pi/share/my_usb auto defaults,noexec,umask=0000 0 0 >> /etc/fstab 9 | -------------------------------------------------------------------------------- /vimrc: -------------------------------------------------------------------------------- 1 | let b:did_ftplugin = 1 2 | set term=ansi 3 | 4 | " Use color syntax highlighting. 5 | syntax on 6 | 7 | " Color specifications. Change them as you would like. 8 | hi Comment term=none ctermfg=blue guifg=gray 9 | hi Constant term=underline ctermfg=cyan guifg=cyan 10 | hi Identifier term=underline ctermfg=green guifg=white 11 | hi Statement term=bold ctermfg=gray guifg=white 12 | hi PreProc term=underline ctermfg=magenta guifg=magenta 13 | hi Type term=underline ctermfg=red guifg=white 14 | hi Special term=bold ctermfg=yellow guifg=blue 15 | hi Search term=bold ctermfg=black ctermbg=yellow 16 | hi Nontext term=bold ctermfg=red guifg=red 17 | hi Normal term=none ctermfg=white guifg=white 18 | 19 | " Special highlighting for XML 20 | hi xmlTag ctermfg=blue cterm=bold guifg=white 21 | hi xmlTagName ctermfg=blue cterm=bold guifg=white 22 | hi xmlEndTag ctermfg=blue cterm=bold guifg=white 23 | 24 | 25 | " Options. 26 | 27 | set autoindent 28 | set backspace=2 " Allows insert-mode backspace to work as one expects 29 | set cindent 30 | set cinkeys=0{,0},:,!^F,o,O,e " See "cinkeys"; this stops "#" from indenting 31 | set fileformat=unix " No crazy CR/LF 32 | set mouse= " I don't like the mouse in VIM 33 | set nobackup " Don't use a backup file (also see writebackup) 34 | set hlsearch " highlight search terms 35 | set nojoinspaces " One space after a "." rather than 2 36 | set ruler " Show the line position at the bottom of the window 37 | set scrolloff=1 " Minimum lines between cursor and window edge 38 | set shiftwidth=2 " Indent by 4 columns (for C functions, etc). 39 | set showcmd " Show partially typed commands 40 | set showmatch " Show parentheses matching 41 | set smartindent " Indent settings (really only the cindent matters) 42 | set textwidth=80 " Maximum line width 43 | set viminfo='0,\"100, " Stay at the start of a file when opening it 44 | set whichwrap=<,>,[,],h,l " Allows for left/right keys to wrap across lines 45 | set writebackup " Write temporary backup files in case we crash 46 | set incsearch 47 | 48 | set foldenable " 49 | set foldmethod=syntax " 50 | set foldcolumn=0 " 51 | setlocal foldlevel=1 " 52 | set foldlevelstart=99 " almost disable 53 | "set foldclose=all " 54 | nnoremap @=((foldclosed(line('.')) < 0) ? 'zc' : 'zo') 55 | 56 | 57 | if version >= 600 58 | 59 | " Vim 6 options 60 | 61 | " colo cduan 62 | set formatoptions=tcroql 63 | 64 | " Increase the highlighting accuracy 65 | syn sync fromstart 66 | 67 | else 68 | 69 | set fo=tcroql 70 | " source ~/.vim/colors/cduan.vim 71 | " source ~/.vim/plugin/matchit.vim 72 | syn sync minlines=1000 73 | 74 | end 75 | 76 | set guifont=-Schumacher-Clean-Medium-R-Normal--16-160-75-75-C-80-ISO646.1991-IRV 77 | 78 | map 79 | imap 80 | 81 | " My file types. TODO: These should be in the .vimft file, I think... 82 | au BufNewFile,BufRead *.cls set syn=tex 83 | au BufNewFile,BufRead *.R set syn=r 84 | au BufNewFile,BufRead *.R syn sync fromstart 85 | 86 | " On plain text files, no keyword chars, because we don't want tab completion 87 | au BufNewFile,BufRead *.txt set iskeyword= 88 | 89 | " NOTE: Sweave syntax is my own file... 90 | au BufNewFile,BufRead *.Snw set syn=sweave 91 | 92 | " On LaTeX files don't use indenting. 93 | au BufNewFile,BufRead *.tex,*.Snw set noautoindent nosmartindent nocindent 94 | " On HTML files don't use indenting. 95 | au BufNewFile,BufRead *.html set noautoindent nosmartindent nocindent 96 | 97 | " On CGI files, determine type by reading in a line. 98 | fun! CGICheck() 99 | let l = getline(nextnonblank(1)) 100 | if l =~ 'php' 101 | set syn=php 102 | elseif l =~ 'perl' 103 | set syn=perl 104 | endif 105 | endfun 106 | 107 | au BufRead *.cgi call CGICheck() 108 | 109 | " On reading TeX files, don't wrap to eighty characters. I know this is 110 | " horrible, but it makes formatting and parsing much easier for me. 111 | " TODO Figure out how to make the scrolling work properly with line wrapping. 112 | fun! TeXformat() 113 | set noautoindent nosmartindent nocindent 114 | set textwidth=0 115 | set linebreak 116 | set display=lastline 117 | noremap j gj 118 | noremap k gk 119 | noremap $ g$ 120 | noremap ^ g^ 121 | noremap 0 g0 122 | noremap A g$a 123 | noremap I g^i 124 | noremap C cg$ 125 | noremap D dg$ 126 | endfun 127 | 128 | "au BufNewFile,BufRead *.tex call TeXformat() 129 | 130 | " Set expandtab for Fortran files 131 | au BufNewFile,BufRead *.f,*.for set expandtab 132 | 133 | " I don't know why I need this... 134 | augroup cprog 135 | au! 136 | augroup end 137 | 138 | " Based on VIM tip 102: automatic tab completion of keywords 139 | function InsertTabWrapper(dir) 140 | let col = col('.') - 1 141 | if !col || getline('.')[col - 1] !~ '\k' 142 | return "\" 143 | elseif "back" == a:dir 144 | return "\" 145 | else 146 | return "\" 147 | endif 148 | endfunction 149 | 150 | inoremap =InsertTabWrapper("fwd") 151 | inoremap =InsertTabWrapper("back") 152 | 153 | set encoding=utf-8 154 | -------------------------------------------------------------------------------- /webssh/install.sh: -------------------------------------------------------------------------------- 1 | # https://github.com/huashengdun/webssh 2 | # https://webssh.huashengdun.org/ 3 | 4 | sudo apt-get install libffi-dev 5 | pip install webssh 6 | 7 | mkdir /home/pi/bin/ 8 | basepath=$(cd `dirname $0`; pwd) 9 | ln -s $basepath/wssh ~/bin/wssh 10 | 11 | screen -dmS wssh ~/bin/wssh #run background 12 | # Open your browser, navigate to 127.0.0.1:8888 13 | # http://10.10.10.224:8888/?hostname=ssh.zhuxiaobo.ml&port=56675&username=pi&password=*** 14 | -------------------------------------------------------------------------------- /webssh/run.py: -------------------------------------------------------------------------------- 1 | from webssh.main import main 2 | 3 | 4 | if __name__ == '__main__': 5 | main() -------------------------------------------------------------------------------- /webssh/wssh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | from webssh.main import main 3 | main() 4 | -------------------------------------------------------------------------------- /zsh/.zshrc: -------------------------------------------------------------------------------- 1 | # If you come from bash you might have to change your $PATH. 2 | export PATH=$HOME/bin:/usr/local/bin:$PATH 3 | 4 | # Path to your oh-my-zsh installation. 5 | export ZSH=/home/pi/.oh-my-zsh 6 | 7 | # Set name of the theme to load. Optionally, if you set this to "random" 8 | # it'll load a random theme each time that oh-my-zsh is loaded. 9 | # See https://github.com/robbyrussell/oh-my-zsh/wiki/Themes 10 | ZSH_THEME="agnoster" 11 | 12 | # Set list of themes to load 13 | # Setting this variable when ZSH_THEME=random 14 | # cause zsh load theme from this variable instead of 15 | # looking in ~/.oh-my-zsh/themes/ 16 | # An empty array have no effect 17 | # ZSH_THEME_RANDOM_CANDIDATES=( "robbyrussell" "agnoster" ) 18 | 19 | # Uncomment the following line to use case-sensitive completion. 20 | # CASE_SENSITIVE="true" 21 | 22 | # Uncomment the following line to use hyphen-insensitive completion. Case 23 | # sensitive completion must be off. _ and - will be interchangeable. 24 | # HYPHEN_INSENSITIVE="true" 25 | 26 | # Uncomment the following line to disable bi-weekly auto-update checks. 27 | # DISABLE_AUTO_UPDATE="true" 28 | 29 | # Uncomment the following line to change how often to auto-update (in days). 30 | # export UPDATE_ZSH_DAYS=13 31 | 32 | # Uncomment the following line to disable colors in ls. 33 | # DISABLE_LS_COLORS="true" 34 | 35 | # Uncomment the following line to disable auto-setting terminal title. 36 | # DISABLE_AUTO_TITLE="true" 37 | 38 | # Uncomment the following line to enable command auto-correction. 39 | # ENABLE_CORRECTION="true" 40 | 41 | # Uncomment the following line to display red dots whilst waiting for completion. 42 | # COMPLETION_WAITING_DOTS="true" 43 | 44 | # Uncomment the following line if you want to disable marking untracked files 45 | # under VCS as dirty. This makes repository status check for large repositories 46 | # much, much faster. 47 | # DISABLE_UNTRACKED_FILES_DIRTY="true" 48 | 49 | # Uncomment the following line if you want to change the command execution time 50 | # stamp shown in the history command output. 51 | # The optional three formats: "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd" 52 | # HIST_STAMPS="mm/dd/yyyy" 53 | 54 | # Would you like to use another custom folder than $ZSH/custom? 55 | # ZSH_CUSTOM=/path/to/new-custom-folder 56 | 57 | # Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*) 58 | # Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/ 59 | # Example format: plugins=(rails git textmate ruby lighthouse) 60 | # Add wisely, as too many plugins slow down shell startup. 61 | plugins=( 62 | git 63 | ) 64 | 65 | source $ZSH/oh-my-zsh.sh 66 | 67 | # User configuration 68 | 69 | # export MANPATH="/usr/local/man:$MANPATH" 70 | 71 | # You may need to manually set your language environment 72 | # export LANG=en_US.UTF-8 73 | 74 | # Preferred editor for local and remote sessions 75 | # if [[ -n $SSH_CONNECTION ]]; then 76 | # export EDITOR='vim' 77 | # else 78 | # export EDITOR='mvim' 79 | # fi 80 | 81 | # Compilation flags 82 | # export ARCHFLAGS="-arch x86_64" 83 | 84 | # ssh 85 | # export SSH_KEY_PATH="~/.ssh/rsa_id" 86 | 87 | # Set personal aliases, overriding those provided by oh-my-zsh libs, 88 | # plugins, and themes. Aliases can be placed here, though oh-my-zsh 89 | # users are encouraged to define aliases within the ZSH_CUSTOM folder. 90 | # For a full list of active aliases, run `alias`. 91 | # 92 | # Example aliases 93 | # alias zshconfig="mate ~/.zshrc" 94 | # alias ohmyzsh="mate ~/.oh-my-zsh" 95 | alias gz='tar -xzvf' 96 | alias tgz='tar -xzvf' 97 | alias zip='unzip' 98 | alias bz2='tar -xjvf' 99 | alias grep="grep --color=auto" 100 | alias vi='vim' 101 | alias ll='ls -l' 102 | alias la='ls -a' 103 | alias node='nodejs' 104 | alias lp='netstat -tunlp' #查看端口占用情况 105 | alias rn='sudo /etc/init.d/networking restart' #重启网络 106 | -------------------------------------------------------------------------------- /树莓派wifi助手/README.md: -------------------------------------------------------------------------------- 1 | APP下载地址:https://itunes.apple.com/cn/app/shu-mei-pai-zhu-shou/id1110826090?l=zh&ls=1&mt=8 2 | 3 | 树莓派助手可以帮助树莓派3通过手机APP设置WiFi连接,下面是树莓派接收端的安装过程 4 | ```bash 5 | sudo apt-get install nodejs bluetooth bluez libbluetooth-dev libudev-dev 6 | sudo ln -s /usr/bin/nodejs /usr/bin/node 7 | git clone https://github.com/emptyhua/raspberry_pi_helper.git 8 | cd ./raspberry_pi_helper 9 | npm install 10 | sudo ./start_pihelper.py 11 | ``` 12 | 安装成功后,下载树莓派助手APP,便可以搜索到树莓派。调试成功后便可以将start_pihelper.py设置开机自启。 13 | -------------------------------------------------------------------------------- /树莓派wifi助手/install.sh: -------------------------------------------------------------------------------- 1 | # https://github.com/emptyhua/raspberry_pi_helper 2 | # 手机端蓝牙连接树莓派设置wifi用 3 | # 蓝牙连接教程:https://blog.csdn.net/guzhong10/article/details/78574577 4 | 5 | sudo apt-get install nodejs bluetooth bluez libbluetooth-dev libudev-dev 6 | sudo ln -s /usr/bin/nodejs /usr/bin/node 7 | git clone https://github.com/emptyhua/raspberry_pi_helper.git 8 | cd ./raspberry_pi_helper 9 | npm install 10 | sudo ./start_pihelper.py --------------------------------------------------------------------------------