Raspberry PIでデジタルサイネージ

# Raspberry PIでデジタルサイネージを作ろう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274715/97df2461-a9fa-92a8-5a03-9c9c833b4bdd.png)
##縦看板にするためのHDMI出力設定
## /boot/config.txt に設定を追加
```/boot/config.txt
display_rotate=1 #追加することにより縦方向表示になる。
```
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">デジタルサイネージ開発中 <a href="https://t.co/x0AcrZoqDh">pic.twitter.com/x0AcrZoqDh</a></p>&mdash; utaca.rich (@RichUtaka) <a href="https://twitter.com/RichUtaka/status/1137217302452006914?ref_src=twsrc%5Etfw">June 8, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#プログラムからChromeを起動制御するためには、Selenium Chrome webdriverが必要です。
```
$ mkdir chrome
$ cd chrome
# sudo pip install selenium
# wget http://launchpadlibrarian.net/361669488/chromium-chromedriver_65.0.3325.181-0ubuntu0.14.04.1_armhf.deb
# sudo dpkg -i chromium-chromedriver_65.0.3325.181-0ubuntu0.14.04.1_armhf.deb
```


# [visual studio 2017を使ってcoding 参照](https://qiita.com/hiratarich/items/c4e17b54fda7919adc14)
### テンプレートを使ってさくっと出来上がり
#### static/contには、表示するコンテント
```
.
├── DigitalSignage.pyproj
├── app.py
├── comm.py
├── routes.py
├── static
│   ├── cont
│   │   ├── Raspberries.jpg
│   │   ├── Raspberries1.jpg
│   │   ├── Raspberries2.jpg
│   │   ├── Raspberries3.jpg
│   │   └── Raspberries4.jpg
│   ├── content
│   │   ├── bootstrap.css
│   │   ├── bootstrap.min.css
│   │   └── site.css
│   ├── favicon.ico
│   ├── fonts
│   │   ├── glyphicons-halflings-regular.eot
│   │   ├── glyphicons-halflings-regular.svg
│   │   ├── glyphicons-halflings-regular.ttf
│   │   └── glyphicons-halflings-regular.woff
│   └── scripts
│       ├── _references.js
│       ├── bootstrap.js
│       ├── bootstrap.min.js
│       ├── jquery-1.10.2.intellisense.js
│       ├── jquery-1.10.2.js
│       ├── jquery-1.10.2.min.js
│       ├── jquery-1.10.2.min.map
│       ├── jquery.validate-vsdoc.js
│       ├── jquery.validate.js
│       ├── jquery.validate.min.js
│       ├── jquery.validate.unobtrusive.js
│       ├── jquery.validate.unobtrusive.min.js
│       ├── modernizr-2.6.2.js
│       ├── respond.js
│       └── respond.min.js
└── views
    ├── index.tpl
    └── layout.tpl

6 directories, 35 files
```

# ソースの中身は、[github](https://github.com/yutakahirata/DigitalSignage)
``` app.py
"""
This script runs the application using a development server.
"""

import bottle,sys,os,time,threading
from selenium import webdriver
os.environ['DISPLAY']=':0'          #HDMI出力設定
os.environ['SERVER_HOST']='0.0.0.0' #webserver 設定
os.environ['SERVER_PORT']='8890'　　#webserver port設定
# chrome 自動起動設定
import comm
comm.options = webdriver.ChromeOptions()
comm.options.add_argument("--kiosk")
comm.options.add_argument("--disable-infobars")	
comm.browser = webdriver.Chrome(chrome_options=comm.options,executable_path="/usr/bin/chromedriver")

# routes contains the HTTP handlers for our server and must be imported.
import routes

if '--debug' in sys.argv[1:] or 'SERVER_DEBUG' in os.environ:
    # Debug mode will enable more verbose output in the console window.
    # It must be set at the beginning of the script.
    bottle.debug(True)

def wsgi_app():
    """Returns the application to make available through wfastcgi. This is used
    when the site is published to Microsoft Azure."""
    return bottle.default_app()

if __name__ == '__main__':
    PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
    STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static').replace('\\', '/')
    HOST = os.environ.get('SERVER_HOST', 'localhost')
    try:
        PORT = int(os.environ.get('SERVER_PORT', '5555'))
    except ValueError:
        PORT = 5555

    @bottle.route('/static/<filepath:path>')
    def server_static(filepath):
        """Handler for static files, used with the development server.
        When running under a production server such as IIS or Apache,
        the server should be configured to serve the static files."""
        return bottle.static_file(filepath, root=STATIC_ROOT)
    def geturl():
        time.sleep(1)
        comm.browser.get('http://%s:%s/'%(HOST,PORT))
        time.sleep(1)
        comm.browser.execute_script("document.body.style.zoom = '75%'")
    th = threading.Thread(target=geturl)
    th.start()
    # Starts a local test server.
    bottle.run(server='wsgiref', host=HOST, port=PORT)

```
関数間共有変数(selenium用)

``` comm.py
def init():
    global browser,options

```
``` routes.py
"""
Routes and views for the bottle application.
"""

from bottle import route, view
from datetime import datetime
import os

@route('/')
@route('/home')
@view('index')
def home():
    """Renders the home page."""
    lst=os.listdir("./static/cont") #/staic/cont配下にコンテンツ用画像ファイルがある
    return dict(
        year=datetime.now().year,pict = lst
    )
# テンプレートにある以下のファイルは、削除

```
上部には、時計と天気をウィジェット表示
### [時計ウィジェット](https://24timezones.com/clock-widget)
### [天気ウィジェット](https://booked.jp/widgets/weather#lite)

```index.tpl
% rebase('layout.tpl', title='Home Page', year=year)

<div class="jumbotron">
<div class="row">
<!--時計の表示-->
	<div class="col-md-4">
	<div class="cleanslate w24tz-current-time w24tz-large" style="display: inline-block !important; visibility: hidden !important; min-width:300px !important; min-height:145px !important;"><p><a href="//24timezones.com/ja_time/japan_chiba_clock.php" style="text-decoration: none" class="clock24" id="tz24-1559793488-c213600-eyJob3VydHlwZSI6MTIsInNob3dkYXRlIjoiMSIsInNob3dzZWNvbmRzIjoiMSIsImNvbnRhaW5lcl9pZCI6ImNsb2NrX2Jsb2NrX2NiNWNmODhmNTA3NGNmNSIsInR5cGUiOiJkYiIsImxhbmciOiJqYSJ9" title="千葉 世界時計" target="_blank" rel="nofollow">千葉の現在の時刻</a></p><div id="clock_block_cb5cf88f5074cf5"></div></div>
	<script type="text/javascript" src="//w.24timezones.com/l.js" async></script>
	</div>
<!--天気予報の表示-->
	<div class="col-md-4">
	<!-- weather widget start --><div id="m-booked-weather-bl250-22795"> <div class="booked-wzs-250-175 weather-customize" style="background-color:#707d8a;width:250px;" id="width1"> <div class="booked-wzs-250-175_in"> <div class="booked-wzs-250-175-data"> <div class="booked-wzs-250-175-left-img wrz-03"> <a target="_blank" href="https://www.booked.net/"> <img src="//s.bookcdn.com/images/letter/logo.gif" alt="booked.net" /> </a> </div> <div class="booked-wzs-250-175-right"> <div class="booked-wzs-day-deck"> <div class="booked-wzs-day-val"> <div class="booked-wzs-day-number"><span class="plus">+</span>19</div> <div class="booked-wzs-day-dergee"> <div class="booked-wzs-day-dergee-val">&deg;</div> <div class="booked-wzs-day-dergee-name">C</div> </div> </div> <div class="booked-wzs-day"> <div class="booked-wzs-day-d">H: <span class="plus">+</span>28&deg;</div> <div class="booked-wzs-day-n">L: <span class="plus">+</span>20&deg;</div> </div> </div> <div class="booked-wzs-250-175-info"> <div class="booked-wzs-250-175-city">千葉市 </div> <div class="booked-wzs-250-175-date">木曜日, 06 6月</div> <div class="booked-wzs-left"> <span class="booked-wzs-bottom-l">週間天気予報を見る</span> </div> </div> </div> </div> <a target="_blank" href="https://booked.jp/weather/chiba-19689"> <table cellpadding="0" cellspacing="0" class="booked-wzs-table-250"> <tr> <td>水</td> <td>金</td> <td>土</td> <td>日</td> <td>月</td> <td>火</td> </tr> <tr> <td class="week-day-ico"><div class="wrz-sml wrzs-01"></div></td> <td class="week-day-ico"><div class="wrz-sml wrzs-18"></div></td> <td class="week-day-ico"><div class="wrz-sml wrzs-18"></div></td> <td class="week-day-ico"><div class="wrz-sml wrzs-18"></div></td> <td class="week-day-ico"><div class="wrz-sml wrzs-03"></div></td> <td class="week-day-ico"><div class="wrz-sml wrzs-18"></div></td> </tr> <tr> <td class="week-day-val"><span class="plus">+</span>19&deg;</td> <td class="week-day-val"><span class="plus">+</span>24&deg;</td> <td class="week-day-val"><span class="plus">+</span>27&deg;</td> <td class="week-day-val"><span class="plus">+</span>22&deg;</td> <td class="week-day-val"><span class="plus">+</span>24&deg;</td> <td class="week-day-val"><span class="plus">+</span>25&deg;</td> </tr> <tr> <td class="week-day-val"><span class="plus">+</span>19&deg;</td> <td class="week-day-val"><span class="plus">+</span>21&deg;</td> <td class="week-day-val"><span class="plus">+</span>21&deg;</td> <td class="week-day-val"><span class="plus">+</span>21&deg;</td> <td class="week-day-val"><span class="plus">+</span>21&deg;</td> <td class="week-day-val"><span class="plus">+</span>21&deg;</td> </tr> </table> </a> </div></div> </div><script type="text/javascript"> var css_file=document.createElement("link"); css_file.setAttribute("rel","stylesheet"); css_file.setAttribute("type","text/css"); css_file.setAttribute("href",'https://s.bookcdn.com/css/w/booked-wzs-widget-275.css?v=0.0.1'); document.getElementsByTagName("head")[0].appendChild(css_file); function setWidgetData(data) { if(typeof(data) != 'undefined' && data.results.length > 0) { for(var i = 0; i < data.results.length; ++i) { var objMainBlock = document.getElementById('m-booked-weather-bl250-22795'); if(objMainBlock !== null) { var copyBlock = document.getElementById('m-bookew-weather-copy-'+data.results[i].widget_type); objMainBlock.innerHTML = data.results[i].html_code; if(copyBlock !== null) objMainBlock.appendChild(copyBlock); } } } else { alert('data=undefined||data.results is empty'); } } </script> <script type="text/javascript" charset="UTF-8" src="https://widgets.booked.net/weather/info?action=get_weather_info&ver=6&cityID=19689&type=3&scode=124&ltid=3458&domid=587&anc_id=64726&cmetric=1&wlangID=16&color=707d8a&wwidth=250&header_color=ffffff&text_color=333333&link_color=08488D&border_form=1&footer_color=ffffff&footer_text_color=333333&transparent=0"></script><!-- weather widget end --></div>
	</div>
	<div class="col-md-4">
	</div>
</div>
<!--サイネージの表示-->
<div class="container">
  <div id="myCarousel" class="carousel slide" data-ride="carousel">
     <ol class="carousel-indicators">
		%for i,x in enumerate(pict):
        %it="class='active'" if i==0 else ""
        <li data-target="#myCarousel" data-slide-to="{{i}} {{it}}"></li>
        %end
	 </ol>
    <div class="carousel-inner">
        %for i,x in enumerate(pict):
        %it="active" if i==0 else ""
        <div class="item {{it}}">
            <img src="/static/cont/{{x}}" alt="{{x}}" style="width:100%;">
        </div>
        %end
    </div>

    <!-- Left and right controls -->
    <a class="left carousel-control" href="#myCarousel" data-slide="prev">
      <span class="glyphicon glyphicon-chevron-left"></span>
      <span class="sr-only">Previous</span>
    </a>
    <a class="right carousel-control" href="#myCarousel" data-slide="next">
      <span class="glyphicon glyphicon-chevron-right"></span>
      <span class="sr-only">Next</span>
    </a>
  </div>
</div>

```

```
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ title }} - Message Application</title>
    <link rel="stylesheet" type="text/css" href="/static/content/bootstrap.min.css" />
    <link rel="stylesheet" type="text/css" href="/static/content/site.css" />
	<link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico" />
    <script src="/static/scripts/modernizr-2.6.2.js"></script>
	<script src="/static/scripts/jquery-1.10.2.js"></script>
    <script src="/static/scripts/bootstrap.js"></script>
    <script src="/static/scripts/respond.js"></script>
</head>

<body>
    <div class="container body-content">
        {{!base}}
    </div>
	</body>
</html>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274715/8a2f637b-d4ca-f299-5e07-032783a46f7d.png)