yannstatic/static/2018/11/28/RaspberryPI-Raspbian-FlashDriveUSB3-RealTimeClock-EcranTactile2p8SPI.html

3160 lines
232 KiB
HTML
Raw Normal View History

2024-10-31 20:18:37 +01:00
<!DOCTYPE html><html lang="fr">
<head><meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>Raspbian Raspberry PI 3 + USB 3.0 Flash Drive FIT 32GB + "Real Time Clock" + écran tactile TFT LCD 2.8" - YannStatic</title>
<meta name="description" content="Raspberry PI 3">
<link rel="canonical" href="https://static.rnmkcy.eu/2018/11/28/RaspberryPI-Raspbian-FlashDriveUSB3-RealTimeClock-EcranTactile2p8SPI.html"><link rel="alternate" type="application/rss+xml" title="YannStatic" href="/feed.xml">
<!-- - include head/favicon.html - -->
<link rel="shortcut icon" type="image/png" href="/assets/favicon/favicon.png"><link rel="stylesheet" href="/assets/css/main.css"><link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" ><!-- start custom head snippets --><link rel="stylesheet" href="/assets/css/expand.css">
<!-- end custom head snippets --><script>(function() {
window.isArray = function(val) {
return Object.prototype.toString.call(val) === '[object Array]';
};
window.isString = function(val) {
return typeof val === 'string';
};
window.hasEvent = function(event) {
return 'on'.concat(event) in window.document;
};
window.isOverallScroller = function(node) {
return node === document.documentElement || node === document.body || node === window;
};
window.isFormElement = function(node) {
var tagName = node.tagName;
return tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
};
window.pageLoad = (function () {
var loaded = false, cbs = [];
window.addEventListener('load', function () {
var i;
loaded = true;
if (cbs.length > 0) {
for (i = 0; i < cbs.length; i++) {
cbs[i]();
}
}
});
return {
then: function(cb) {
cb && (loaded ? cb() : (cbs.push(cb)));
}
};
})();
})();
(function() {
window.throttle = function(func, wait) {
var args, result, thisArg, timeoutId, lastCalled = 0;
function trailingCall() {
lastCalled = new Date;
timeoutId = null;
result = func.apply(thisArg, args);
}
return function() {
var now = new Date,
remaining = wait - (now - lastCalled);
args = arguments;
thisArg = this;
if (remaining <= 0) {
clearTimeout(timeoutId);
timeoutId = null;
lastCalled = now;
result = func.apply(thisArg, args);
} else if (!timeoutId) {
timeoutId = setTimeout(trailingCall, remaining);
}
return result;
};
};
})();
(function() {
var Set = (function() {
var add = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (data[i] === item) {
return;
}
}
this.size ++;
data.push(item);
return data;
};
var Set = function(data) {
this.size = 0;
this._data = [];
var i;
if (data.length > 0) {
for (i = 0; i < data.length; i++) {
add.call(this, data[i]);
}
}
};
Set.prototype.add = add;
Set.prototype.get = function(index) { return this._data[index]; };
Set.prototype.has = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (this.get(i) === item) {
return true;
}
}
return false;
};
Set.prototype.is = function(map) {
if (map._data.length !== this._data.length) { return false; }
var i, j, flag, tData = this._data, mData = map._data;
for (i = 0; i < tData.length; i++) {
for (flag = false, j = 0; j < mData.length; j++) {
if (tData[i] === mData[j]) {
flag = true;
break;
}
}
if (!flag) { return false; }
}
return true;
};
Set.prototype.values = function() {
return this._data;
};
return Set;
})();
window.Lazyload = (function(doc) {
var queue = {js: [], css: []}, sources = {js: {}, css: {}}, context = this;
var createNode = function(name, attrs) {
var node = doc.createElement(name), attr;
for (attr in attrs) {
if (attrs.hasOwnProperty(attr)) {
node.setAttribute(attr, attrs[attr]);
}
}
return node;
};
var end = function(type, url) {
var s, q, qi, cbs, i, j, cur, val, flag;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
s[url] = true;
for (i = 0; i < q.length; i++) {
cur = q[i];
if (cur.urls.has(url)) {
qi = cur, val = qi.urls.values();
qi && (cbs = qi.callbacks);
for (flag = true, j = 0; j < val.length; j++) {
cur = val[j];
if (!s[cur]) {
flag = false;
}
}
if (flag && cbs && cbs.length > 0) {
for (j = 0; j < cbs.length; j++) {
cbs[j].call(context);
}
qi.load = true;
}
}
}
}
};
var load = function(type, urls, callback) {
var s, q, qi, node, i, cur,
_urls = typeof urls === 'string' ? new Set([urls]) : new Set(urls), val, url;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
for (i = 0; i < q.length; i++) {
cur = q[i];
if (_urls.is(cur.urls)) {
qi = cur;
break;
}
}
val = _urls.values();
if (qi) {
callback && (qi.load || qi.callbacks.push(callback));
callback && (qi.load && callback());
} else {
q.push({
urls: _urls,
callbacks: callback ? [callback] : [],
load: false
});
for (i = 0; i < val.length; i++) {
node = null, url = val[i];
if (s[url] === undefined) {
(type === 'js' ) && (node = createNode('script', { src: url }));
(type === 'css') && (node = createNode('link', { rel: 'stylesheet', href: url }));
if (node) {
node.onload = (function(type, url) {
return function() {
end(type, url);
};
})(type, url);
(doc.head || doc.body).appendChild(node);
s[url] = false;
}
}
}
}
}
};
return {
js: function(url, callback) {
load('js', url, callback);
},
css: function(url, callback) {
load('css', url, callback);
}
};
})(this.document);
})();
</script><script>
(function() {
var TEXT_VARIABLES = {
version: '2.2.6',
sources: {
font_awesome: 'https://use.fontawesome.com/releases/v5.0.13/css/all.css',
jquery: '/assets/js/jquery.min.js',
leancloud_js_sdk: '//cdn.jsdelivr.net/npm/leancloud-storage@3.13.2/dist/av-min.js',
chart: 'https://cdn.bootcss.com/Chart.js/2.7.2/Chart.bundle.min.js',
gitalk: {
js: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.js',
css: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.css'
},
valine: 'https://unpkg.com/valine/dist/Valine.min.js'
},
site: {
toc: {
selectors: 'h1,h2,h3'
}
},
paths: {
search_js: '/assets/search.js'
}
};
window.TEXT_VARIABLES = TEXT_VARIABLES;
})();
</script>
</head>
<body>
<div class="root" data-is-touch="false">
<div class="layout--page js-page-root"><!----><div class="page__main js-page-main page__viewport hide-footer has-aside has-aside cell cell--auto">
<div class="page__main-inner"><div class="page__header d-print-none"><header class="header"><div class="main">
<div class="header__title">
<div class="header__brand"><svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="478.9473684210526" viewBox="0, 0, 400,478.9473684210526"><g id="svgg"><path id="path0" d="M308.400 56.805 C 306.970 56.966,303.280 57.385,300.200 57.738 C 290.906 58.803,278.299 59.676,269.200 59.887 L 260.600 60.085 259.400 61.171 C 258.010 62.428,256.198 63.600,255.645 63.600 C 255.070 63.600,252.887 65.897,252.598 66.806 C 252.460 67.243,252.206 67.600,252.034 67.600 C 251.397 67.600,247.206 71.509,247.202 72.107 C 247.201 72.275,246.390 73.190,245.400 74.138 C 243.961 75.517,243.598 76.137,243.592 77.231 C 243.579 79.293,241.785 83.966,240.470 85.364 C 239.176 86.740,238.522 88.365,237.991 91.521 C 237.631 93.665,236.114 97.200,235.554 97.200 C 234.938 97.200,232.737 102.354,232.450 104.472 C 232.158 106.625,230.879 109.226,229.535 110.400 C 228.933 110.926,228.171 113.162,226.434 119.500 C 226.178 120.435,225.795 121.200,225.584 121.200 C 225.373 121.200,225.200 121.476,225.200 121.813 C 225.200 122.149,224.885 122.541,224.500 122.683 C 223.606 123.013,223.214 123.593,223.204 124.600 C 223.183 126.555,220.763 132.911,219.410 134.562 C 218.443 135.742,217.876 136.956,217.599 138.440 C 217.041 141.424,215.177 146.434,214.532 146.681 C 214.240 146.794,214.000 147.055,214.000 147.261 C 214.000 147.467,213.550 148.086,213.000 148.636 C 212.450 149.186,212.000 149.893,212.000 150.208 C 212.000 151.386,208.441 154.450,207.597 153.998 C 206.319 153.315,204.913 150.379,204.633 147.811 C 204.365 145.357,202.848 142.147,201.759 141.729 C 200.967 141.425,199.200 137.451,199.200 135.974 C 199.200 134.629,198.435 133.224,196.660 131.311 C 195.363 129.913,194.572 128.123,193.870 125.000 C 193.623 123.900,193.236 122.793,193.010 122.540 C 190.863 120.133,190.147 118.880,188.978 115.481 C 188.100 112.928,187.151 111.003,186.254 109.955 C 185.358 108.908,184.518 107.204,183.847 105.073 C 183.280 103.273,182.497 101.329,182.108 100.753 C 181.719 100.177,180.904 98.997,180.298 98.131 C 179.693 97.265,178.939 95.576,178.624 94.378 C 178.041 92.159,177.125 90.326,175.023 87.168 C 174.375 86.196,173.619 84.539,173.342 83.486 C 172.800 81.429,171.529 79.567,170.131 78.785 C 169.654 78.517,168.697 77.511,168.006 76.549 C 167.316 75.587,166.594 74.800,166.402 74.800 C 166.210 74.800,164.869 73.633,163.421 72.206 C 160.103 68.936,161.107 69.109,146.550 69.301 C 133.437 69.474,128.581 70.162,126.618 72.124 C 126.248 72.495,125.462 72.904,124.872 73.033 C 124.282 73.163,123.088 73.536,122.219 73.863 C 121.349 74.191,119.028 74.638,117.061 74.858 C 113.514 75.254,109.970 76.350,108.782 77.419 C 107.652 78.436,100.146 80.400,97.388 80.400 C 95.775 80.400,93.167 81.360,91.200 82.679 C 90.430 83.195,89.113 83.804,88.274 84.031 C 85.875 84.681,78.799 90.910,74.400 96.243 L 73.400 97.456 73.455 106.028 C 73.526 117.055,74.527 121.238,77.820 124.263 C 78.919 125.273,80.400 127.902,80.400 128.842 C 80.400 129.202,81.075 130.256,81.900 131.186 C 83.563 133.059,85.497 136.346,86.039 138.216 C 86.233 138.886,87.203 140.207,88.196 141.153 C 89.188 142.098,90.000 143.104,90.000 143.388 C 90.000 144.337,92.129 148.594,92.869 149.123 C 93.271 149.410,93.600 149.831,93.600 150.059 C 93.600 150.286,93.932 150.771,94.337 151.136 C 94.743 151.501,95.598 153.004,96.237 154.475 C 96.877 155.947,97.760 157.351,98.200 157.596 C 98.640 157.841,99.900 159.943,101.000 162.267 C 102.207 164.817,103.327 166.644,103.825 166.876 C 104.278 167.087,105.065 168.101,105.573 169.130 C 107.658 173.348,108.097 174.093,110.006 176.647 C 111.103 178.114,112.000 179.725,112.000 180.227 C 112.000 181.048,113.425 183.163,114.678 184.200 C 115.295 184.711,117.396 188.733,117.720 190.022 C 117.855 190.562,118.603 191.633,119.381 192.402 C 120.160 193.171,121.496 195.258,122.351 197.039 C 123.206 198.820,124.167 200.378,124.487 200.501 C 124.807 200.624,125.953 202.496,127.034 204.662 C 128.114 206.828,129.676 209.299,130.505 210.153 C 131.333 211.007,132.124 212.177,132.262 212.753 C 132.618 214.239,134.291 217.048,136.288 219.5
" href="/">YannStatic</a></div><!--<button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button>--><!-- <li><button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button></li> -->
<!-- Champ de recherche -->
<div id="searchbox" class="search search--dark" style="visibility: visible">
<div class="main">
<div class="search__header"></div>
<div class="search-bar">
<div class="search-box js-search-box">
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
<input id="search-input" type="text" />
<!-- <div class="search-box__icon-clear js-icon-clear">
<a><i class="fas fa-times"></i></a>
</div> -->
</div>
</div>
</div>
</div>
<!-- Script pointing to search-script.js -->
<script>/*!
* Simple-Jekyll-Search
* Copyright 2015-2020, Christian Fei
* Licensed under the MIT License.
*/
(function(){
'use strict'
var _$Templater_7 = {
compile: compile,
setOptions: setOptions
}
const options = {}
options.pattern = /\{(.*?)\}/g
options.template = ''
options.middleware = function () {}
function setOptions (_options) {
options.pattern = _options.pattern || options.pattern
options.template = _options.template || options.template
if (typeof _options.middleware === 'function') {
options.middleware = _options.middleware
}
}
function compile (data) {
return options.template.replace(options.pattern, function (match, prop) {
const value = options.middleware(prop, data[prop], options.template)
if (typeof value !== 'undefined') {
return value
}
return data[prop] || match
})
}
'use strict';
function fuzzysearch (needle, haystack) {
var tlen = haystack.length;
var qlen = needle.length;
if (qlen > tlen) {
return false;
}
if (qlen === tlen) {
return needle === haystack;
}
outer: for (var i = 0, j = 0; i < qlen; i++) {
var nch = needle.charCodeAt(i);
while (j < tlen) {
if (haystack.charCodeAt(j++) === nch) {
continue outer;
}
}
return false;
}
return true;
}
var _$fuzzysearch_1 = fuzzysearch;
'use strict'
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
function FuzzySearchStrategy () {
this.matches = function (string, crit) {
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
}
}
'use strict'
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
function LiteralSearchStrategy () {
this.matches = function (str, crit) {
if (!str) return false
str = str.trim().toLowerCase()
crit = crit.trim().toLowerCase()
return crit.split(' ').filter(function (word) {
return str.indexOf(word) >= 0
}).length === crit.split(' ').length
}
}
'use strict'
var _$Repository_4 = {
put: put,
clear: clear,
search: search,
setOptions: __setOptions_4
}
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
function NoSort () {
return 0
}
const data = []
let opt = {}
opt.fuzzy = false
opt.limit = 10
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = NoSort
opt.exclude = []
function put (data) {
if (isObject(data)) {
return addObject(data)
}
if (isArray(data)) {
return addArray(data)
}
return undefined
}
function clear () {
data.length = 0
return data
}
function isObject (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
}
function isArray (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
}
function addObject (_data) {
data.push(_data)
return data
}
function addArray (_data) {
const added = []
clear()
for (let i = 0, len = _data.length; i < len; i++) {
if (isObject(_data[i])) {
added.push(addObject(_data[i]))
}
}
return added
}
function search (crit) {
if (!crit) {
return []
}
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
}
function __setOptions_4 (_opt) {
opt = _opt || {}
opt.fuzzy = _opt.fuzzy || false
opt.limit = _opt.limit || 10
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = _opt.sort || NoSort
opt.exclude = _opt.exclude || []
}
function findMatches (data, crit, strategy, opt) {
const matches = []
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
const match = findMatchesInObject(data[i], crit, strategy, opt)
if (match) {
matches.push(match)
}
}
return matches
}
function findMatchesInObject (obj, crit, strategy, opt) {
for (const key in obj) {
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
return obj
}
}
}
function isExcluded (term, excludedTerms) {
for (let i = 0, len = excludedTerms.length; i < len; i++) {
const excludedTerm = excludedTerms[i]
if (new RegExp(excludedTerm).test(term)) {
return true
}
}
return false
}
/* globals ActiveXObject:false */
'use strict'
var _$JSONLoader_2 = {
load: load
}
function load (location, callback) {
const xhr = getXHR()
xhr.open('GET', location, true)
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
xhr.send()
}
function createStateChangeListener (xhr, callback) {
return function () {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
callback(null, JSON.parse(xhr.responseText))
} catch (err) {
callback(err, null)
}
}
}
}
function getXHR () {
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
}
'use strict'
var _$OptionsValidator_3 = function OptionsValidator (params) {
if (!validateParams(params)) {
throw new Error('-- OptionsValidator: required options missing')
}
if (!(this instanceof OptionsValidator)) {
return new OptionsValidator(params)
}
const requiredOptions = params.required
this.getRequiredOptions = function () {
return requiredOptions
}
this.validate = function (parameters) {
const errors = []
requiredOptions.forEach(function (requiredOptionName) {
if (typeof parameters[requiredOptionName] === 'undefined') {
errors.push(requiredOptionName)
}
})
return errors
}
function validateParams (params) {
if (!params) {
return false
}
return typeof params.required !== 'undefined' && params.required instanceof Array
}
}
'use strict'
var _$utils_9 = {
merge: merge,
isJSON: isJSON
}
function merge (defaultParams, mergeParams) {
const mergedOptions = {}
for (const option in defaultParams) {
mergedOptions[option] = defaultParams[option]
if (typeof mergeParams[option] !== 'undefined') {
mergedOptions[option] = mergeParams[option]
}
}
return mergedOptions
}
function isJSON (json) {
try {
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
return true
}
return false
} catch (err) {
return false
}
}
var _$src_8 = {};
(function (window) {
'use strict'
let options = {
searchInput: null,
resultsContainer: null,
json: [],
success: Function.prototype,
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
templateMiddleware: Function.prototype,
sortMiddleware: function () {
return 0
},
noResultsText: 'No results found',
limit: 10,
fuzzy: false,
debounceTime: null,
exclude: []
}
let debounceTimerHandle
const debounce = function (func, delayMillis) {
if (delayMillis) {
clearTimeout(debounceTimerHandle)
debounceTimerHandle = setTimeout(func, delayMillis)
} else {
func.call()
}
}
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
/* removed: const _$Templater_7 = require('./Templater') */;
/* removed: const _$Repository_4 = require('./Repository') */;
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
const optionsValidator = _$OptionsValidator_3({
required: requiredOptions
})
/* removed: const _$utils_9 = require('./utils') */;
window.SimpleJekyllSearch = function (_options) {
const errors = optionsValidator.validate(_options)
if (errors.length > 0) {
throwError('You must specify the following required options: ' + requiredOptions)
}
options = _$utils_9.merge(options, _options)
_$Templater_7.setOptions({
template: options.searchResultTemplate,
middleware: options.templateMiddleware
})
_$Repository_4.setOptions({
fuzzy: options.fuzzy,
limit: options.limit,
sort: options.sortMiddleware,
exclude: options.exclude
})
if (_$utils_9.isJSON(options.json)) {
initWithJSON(options.json)
} else {
initWithURL(options.json)
}
const rv = {
search: search
}
typeof options.success === 'function' && options.success.call(rv)
return rv
}
function initWithJSON (json) {
_$Repository_4.put(json)
registerInput()
}
function initWithURL (url) {
_$JSONLoader_2.load(url, function (err, json) {
if (err) {
throwError('failed to get JSON (' + url + ')')
}
initWithJSON(json)
})
}
function emptyResultsContainer () {
options.resultsContainer.innerHTML = ''
}
function appendToResultsContainer (text) {
options.resultsContainer.innerHTML += text
}
function registerInput () {
options.searchInput.addEventListener('input', function (e) {
if (isWhitelistedKey(e.which)) {
emptyResultsContainer()
debounce(function () { search(e.target.value) }, options.debounceTime)
}
})
}
function search (query) {
if (isValidQuery(query)) {
emptyResultsContainer()
render(_$Repository_4.search(query), query)
}
}
function render (results, query) {
const len = results.length
if (len === 0) {
return appendToResultsContainer(options.noResultsText)
}
for (let i = 0; i < len; i++) {
results[i].query = query
appendToResultsContainer(_$Templater_7.compile(results[i]))
}
}
function isValidQuery (query) {
return query && query.length > 0
}
function isWhitelistedKey (key) {
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
}
function throwError (message) {
throw new Error('SimpleJekyllSearch --- ' + message)
}
})(window)
}());
</script>
<!-- Configuration -->
<script>
SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
json: '/search.json',
//searchResultTemplate: '<li><a href="https://static.rnmkcy.eu{url}">{date}&nbsp;{title}</a></li>'
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{title}</a></li>'
})
</script>
<!-- Fin déclaration champ de recherche --></div><nav class="navigation">
<ul><li class="navigation__item"><a href="/archive.html">Etiquettes</a></li><li class="navigation__item"><a href="/htmldoc.html">Documents</a></li><li class="navigation__item"><a href="/liens_ttrss.html">Liens</a></li><li class="navigation__item"><a href="/aide-jekyll-text-theme.html">Aide</a></li></ul>
</nav></div>
</header>
</div><div class="page__content"><div class ="main"><div class="grid grid--reverse">
<div class="col-main cell cell--auto"><!-- start custom main top snippet --><div id="results-container" class="search-result js-search-result"></div><!-- end custom main top snippet -->
<article itemscope itemtype="http://schema.org/Article"><div class="article__header"><header><h1 style="color:Tomato;">Raspbian Raspberry PI 3 + USB 3.0 Flash Drive FIT 32GB + "Real Time Clock" + écran tactile TFT LCD 2.8"</h1></header></div><meta itemprop="headline" content="Raspbian Raspberry PI 3 + USB 3.0 Flash Drive FIT 32GB + "Real Time Clock" + écran tactile TFT LCD 2.8""><div class="article__info clearfix"><ul class="left-col menu"><li>
<a class="button button--secondary button--pill button--sm"
href="/archive.html?tag=raspberry">raspberry</a>
</li></ul><ul class="right-col menu"><li>
<i class="far fa-calendar-alt"></i>&nbsp;<span title="Création" style="color:#FF00FF">28&nbsp;nov.&nbsp;&nbsp;2018</span>
<span title="Modification" style="color:#00FF7F">&nbsp;4&nbsp;mai&nbsp;&nbsp;&nbsp;2019</span></li></ul></div><meta itemprop="datePublished" content="2019-05-04T00:00:00+02:00">
<meta itemprop="keywords" content="raspberry"><div class="js-article-content">
<div class="layout--article"><!-- start custom article top snippet -->
<style>
#myBtn {
display: none;
position: fixed;
bottom: 10px;
right: 10px;
z-index: 99;
font-size: 12px;
font-weight: bold;
border: none;
outline: none;
background-color: white;
color: black;
cursor: pointer;
padding: 5px;
border-radius: 4px;
}
#myBtn:hover {
background-color: #555;
}
</style>
<button onclick="topFunction()" id="myBtn" title="Haut de page">&#8679;</button>
<script>
//Get the button
var mybutton = document.getElementById("myBtn");
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
mybutton.style.display = "block";
} else {
mybutton.style.display = "none";
}
}
// When the user clicks on the button, scroll to the top of the document
function topFunction() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}
</script>
<!-- end custom article top snippet -->
<div class="article__content" itemprop="articleBody"><details>
<summary><b>Afficher/cacher Sommaire</b></summary>
<!-- affichage sommaire -->
<div class="toc-aside js-toc-root"></div>
</details><h2 id="raspberry-pi-3">Raspberry PI 3</h2>
<p><img src="/images/raspberrypi3.jpg" alt="Pin-out" width="500px" /></p>
<ul>
<li>Processeur Quad Core Broadcom 2837 ARMv8 64bit</li>
<li>Vitesse du processeur : 1,2 GHz</li>
<li>1 GB RAM</li>
<li>BCM43143 WiFi intégré</li>
<li>Bluetooth Low Energy (BLE) intégré</li>
<li>40 broches dextension GPIO</li>
<li>4 ports USB2</li>
<li>Sortie vidéo et stéréo</li>
<li>Port caméra CSI pour connecter la caméra Raspberry Pi</li>
<li>Port daffichage DSI pour connecter lécran tactile Raspberry Pi</li>
<li>Lecteur de carte Micro SD pour charger votre système dexploitation et stocker vos données</li>
<li>Source dalimentation Micro USB, supporte maintenant jusquà 2,5A</li>
</ul>
<p><img src="/images/raspbery-pi-3-gpio-pinout-40-pin-header-block-connector-1-1.png" alt="" width="500px" /></p>
<p><a href="https://fr.pinout.xyz/pinout/spi#">SPI0 SPI1 Pin Out</a></p>
<h2 id="raspbian-stretch-lite">Raspbian Stretch Lite</h2>
<p><img src="/images/raspbian-logo.png" alt="" width="100px" /></p>
<p><a href="https://downloads.raspberrypi.org/raspbian_lite_latest">Raspbian Stretch Lite (download)</a></p>
<h3 id="samsung-usb-30-flash-drive-fit-32gb">Samsung USB 3.0 Flash Drive FIT 32GB</h3>
<p>Le Raspberry Pi 3 est capable de booter sur un stockage USB, disque dur externe ou clé USB.</p>
<blockquote>
<p>** /!\ ATTENTION : ** il faut une unité de stockage suffisamment rapide pour être prise en compte</p>
</blockquote>
<p>Choix dune clé <strong>Samsung USB 3.0 Flash Drive FIT 32GB</strong><br />
<img src="/images/samsung-USB-3.0.png" alt="Samsung USB 3.0 Flash Drive FIT 32GB" width="100px" /></p>
<blockquote>
<p>NOTE:La possibilité de booter sur un stockage USB externe est vérifiable après boot sur une carte SD par la commande <code class="language-plaintext highlighter-rouge">vcgencmd otp_dump | grep 17:</code> qui doit afficher <strong>17:3020000a</strong></p>
</blockquote>
<p>Insérer la clé <strong>Samsung USB 3.0 Flash Drive FIT 32GB</strong> sur un des connecteurs USB de lordinateur linux <br />
Repérer sur quel périphérique</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dmesg
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ 3420.876497] sd 4:0:0:0: [sde] 62652416 512-byte logical blocks: (32.1 GB/29.9 GiB)
[ 3420.877074] sd 4:0:0:0: [sde] Write Protect is off
[ 3420.877081] sd 4:0:0:0: [sde] Mode Sense: 43 00 00 00
[ 3420.877653] sd 4:0:0:0: [sde] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[ 3420.884367] sde: sde1 sde2
[ 3420.886547] sd 4:0:0:0: [sde] Attached SCSI removable disk
</code></pre></div></div>
<p>La “Clé USB” est sur le périphérique système /dev/sde</p>
<p>Aller dans le dossier contenant limage de raspbian</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo dd bs=4M if=2019-04-08-raspbian-stretch-lite.img of=/dev/sde conv=fsync
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>445+0 enregistrements lus
445+0 enregistrements écrits
1866465280 octets (1,9 GB, 1,7 GiB) copiés, 145,811 s, 12,8 MB/s
</code></pre></div></div>
<blockquote>
<p><strong>ATTENTION !!!</strong> Pas daccès à la carte raspberry en mode terminal par la liaison série ou SSH<br />
Les dernières versions de Raspbian nécessitent un écran et un clavier, car il nest plus possible de se connecter directement par la liaison série ou SSH au Raspberry par défaut.</p>
<ul>
<li>Pour réactiver le lancement de SSH au boot ,placer dans la partition boot de la carte SD un fichier nommé <strong>ssh</strong>, vide et sans extension.</li>
<li>Pour la liaison série ,il faut modifier le fichier de configuration **config.txt ** avant insertion de la “Clé USB” dans le raspberry</li>
</ul>
</blockquote>
<p>Identifier le périphérique</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dmesg
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ 3420.877074] sd 4:0:0:0: [sde] Write Protect is off
[ 3420.877081] sd 4:0:0:0: [sde] Mode Sense: 43 00 00 00
[ 3420.877653] sd 4:0:0:0: [sde] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[ 3420.884367] sde: sde1 sde2
[ 3420.886547] sd 4:0:0:0: [sde] Attached SCSI removable disk
[ 3664.644705] sde: sde1 sde2
</code></pre></div></div>
<p>Montage de la “Clé USB” (sde1 qui correspond au boot) sur un dossier temporaire :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mkdir -p /mnt/temp #Créer un dossier de montage temporaire
sudo mount /dev/sde1 /mnt/temp #montage de la partition boot sur /mnt/temp
</code></pre></div></div>
<p>Modifier le fichier **temp/config.txt **</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /mnt/temp/config.txt
</code></pre></div></div>
<p>ajouter en fin de fichier pour activer la liasion série</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>enable_uart=1
</code></pre></div></div>
<p>Sauvegarde Crtl x y ou o Entrée<br />
fichier ssh vide dans la partition boot</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo touch /mnt/temp/ssh
</code></pre></div></div>
<p>Démontage et insertion “Clé USB” dans le raspberry :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo umount /mnt/temp
</code></pre></div></div>
<p>Après avoir inséré la “Clé USB” dans son logement ,connecté le cordon réseau et la liaison série puis
brancher la micro-usb dalimentation sur la carte raspberry et enfin le DC-Pack sur le secteur.<br />
On peut se connecter soit par la liaison série (A) ou SSH (B)</p>
<p>A - <strong>minicom</strong> ou <strong>screen</strong> et un adatateur USB/Série</p>
<table>
<thead>
<tr>
<th>Interface USB/Série</th>
<th>Raspberry</th>
</tr>
</thead>
<tbody>
<tr>
<td>GND</td>
<td>6 (GND)</td>
</tr>
<tr>
<td>Rxd</td>
<td>8 (Txd)</td>
</tr>
<tr>
<td>Txd</td>
<td>10 (Rxd)</td>
</tr>
</tbody>
</table>
<p>lancer le logiciel de communication (minicom ou screen)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo minicom # Débit/Parité/Bits:115200 8N1,Contrôle de flux matériel:Non,Contrôle de flux logiciel:Non
sudo screen /dev/ttyUSB0 115200
</code></pre></div></div>
<p>B - Trouver ladresse avec <strong>nmap</strong> et utiliser <strong>ssh</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nmap -T4 -sP 192.168.0.0/24
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[...]
Nmap scan report for 192.168.0.41
Host is up (0.00038s latency).
MAC Address: B8:27:EB:54:7E:6A (Raspberry Pi Foundation)
[...]
</code></pre></div></div>
<p>Connexion SSH</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh pi@192.168.0.41
</code></pre></div></div>
<h3 id="premier-boot-sur-la-clé-usb">Premier boot sur la clé USB</h3>
<p>login/motde passe : pi/raspberry<br />
Relever adresse</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ip addr show
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether b8:27:eb:54:7e:6a brd ff:ff:ff:ff:ff:ff
inet 192.168.0.41/24 brd 192.168.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 2a01:e34:eebf:df0:c26a:5794:27e7:5438/64 scope global mngtmpaddr noprefixroute dynamic
valid_lft 86091sec preferred_lft 86091sec
inet6 fe80::8f2a:faf1:46af:fa09/64 scope link
valid_lft forever preferred_lft forever
3: wlan0: &lt;NO-CARRIER,BROADCAST,MULTICAST,UP&gt; mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
link/ether b8:27:eb:01:2b:3f brd ff:ff:ff:ff:ff:ff
</code></pre></div></div>
<p>Mise à jour du Firmware</p>
<p>Lutilitaire <strong>rpi-update</strong> permet de mettre à jour le Firmware de la carte Raspberry.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install rpi-update
</code></pre></div></div>
<p>Exécution de lutilitaire pour réaliser la mise à jour :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo rpi-update
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> *** Raspberry Pi firmware updater by Hexxeh, enhanced by AndrewS and Dom
*** Performing self-update
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 13545 100 13545 0 0 18675 0 --:--:-- --:--:-- --:--:-- 18682
*** Relaunching after update
*** Raspberry Pi firmware updater by Hexxeh, enhanced by AndrewS and Dom
*** We're running for the first time
*** Backing up files (this will take a few minutes)
*** Backing up firmware
*** Backing up modules 4.14.98-v7+
#############################################################
WARNING: This update bumps to rpi-4.19.y linux tree
Be aware there could be compatibility issues with some drivers
Discussion here:
https://www.raspberrypi.org/forums/viewtopic.php?f=29&amp;t=224931
##############################################################
Would you like to proceed? (y/N)
*** Downloading specific firmware revision (this will take a few minutes)
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 168 0 168 0 0 387 0 --:--:-- --:--:-- --:--:-- 387
100 58.5M 100 58.5M 0 0 817k 0 0:01:13 0:01:13 --:--:-- 832k
*** Updating firmware
*** Updating kernel modules
*** depmod 4.19.37+
*** depmod 4.19.37-v7+
*** Updating VideoCore libraries
*** Using HardFP libraries
*** Updating SDK
*** Running ldconfig
*** Storing current firmware revision
*** Deleting downloaded files
*** Syncing changes to disk
*** If no errors appeared, your firmware was successfully updated to 18e0a0f9a31e7a3a47d9c4301c7705b980ab0516
*** A reboot is needed to activate the new firmware
</code></pre></div></div>
<p>Redémarrage du système :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo reboot
</code></pre></div></div>
<p>Mise à jour des paquets</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt update &amp;&amp; sudo apt -y upgrade
</code></pre></div></div>
<p>Mise à jour distribution Raspbian</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt dist-upgrade
</code></pre></div></div>
<h3 id="paramétrage">Paramétrage</h3>
<p>Connexion <strong>pi/raspberry</strong> via SSH</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh pi@192.168.0.41
</code></pre></div></div>
<h3 id="paramétrage-1">Paramétrage</h3>
<p>Accès configuration raspbian</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo raspi-config
</code></pre></div></div>
<p>Wifi <br />
2 Network Options Configure network settings <br />
N2 Wi-fi Enter SSID and passphrase<br />
Country FR<br />
SSID YANN_2GEXT<br />
Mot de passe</p>
<p>Locales</p>
<p><img src="/images/rpi01.png" alt="" width="600px" /></p>
<p><img src="/images/rpi02.png" alt="" width="600px" /></p>
<p><img src="/images/rpi03.png" alt="" width="600px" /><br />
En cas derreur <strong>locale: Cannot set LC_CTYPE to default locale: No such file or directory</strong> , exécuter:<br />
<code class="language-plaintext highlighter-rouge">export LC_ALL=C</code><br />
<code class="language-plaintext highlighter-rouge">sudo dpkg-reconfigure locales</code></p>
<p><img src="/images/rpi04.png" alt="" width="600px" /></p>
<p>Paramètres régionaux</p>
<p><img src="/images/rpi01.png" alt="" width="600px" /></p>
<p><img src="/images/rpi05.png" alt="" width="600px" /></p>
<p><img src="/images/rpi06.png" alt="" width="600px" /></p>
<p><img src="/images/rpi07.png" alt="" width="600px" /></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>timedatectl
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Local time: Sat 2019-05-04 15:09:49 CEST
Universal time: Sat 2019-05-04 13:09:49 UTC
RTC time: n/a
Time zone: Europe/Paris (CEST, +0200)
Network time on: yes
NTP synchronized: yes
RTC in local TZ: no
</code></pre></div></div>
<p>Clavier fr</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/default/keyboard
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># KEYBOARD CONFIGURATION FILE
# Consult the keyboard(5) manual page.
XKBMODEL="pc105"
XKBLAYOUT="fr"
XKBVARIANT=""
XKBOPTIONS=""
BACKSPACE="guess"
</code></pre></div></div>
<h3 id="utilisateur-et-root">Utilisateur et root</h3>
<p>Su raspbian , tous les utilisateurs qui appartiennent au groupe sudo ont les mêmes droits que root</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>id pi
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>uid=1000(pi) gid=1000(pi) groupes=1000(pi),4(adm),20(dialout),24(cdrom),27(sudo),29(audio),44(video),46(plugdev),60(games),100(users),101(input),108(netdev),999(spi),998(i2c),997(gpio)
</code></pre></div></div>
<p>Changer le mot de passe utilisateur et root</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo passwd pi
sudo passwd root
</code></pre></div></div>
<h3 id="hostname">hostname</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hostnamectl
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Static hostname: raspberrypi
Icon name: computer
Machine ID: 3451d71e19fb4ef787b592b6ada3cd77
Boot ID: 084b078d7ce84c60b084b10cc6a1536f
Operating System: Raspbian GNU/Linux 9 (stretch)
Kernel: Linux 4.14.80-v7+
Architecture: arm
</code></pre></div></div>
<h3 id="exécution-script-sur-connexion-ssh">Exécution script sur connexion SSH</h3>
<p>Exécuter un fichier <em>utilisateur</em> nommé <strong>$HOME/.ssh/rc</strong> si <em>présent</em><br />
Pour <em>tous les utilisateurs</em> exécuter un fichier nommé <strong>/etc/ssh/sshrc</strong> si <em>présent</em><br />
Installer les utilitaires <em>curl jq figlet git</em></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt -y install curl jq figlet git
</code></pre></div></div>
<p>Le batch</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir -p ~/.ssh
nano ~/.ssh/rc
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/bash
#clear
PROCCOUNT=`ps -Afl | wc -l` # nombre de lignes
PROCCOUNT=`expr $PROCCOUNT - 5` # on ote les non concernées
GROUPZ=`users`
ipinfo=$(curl -s ipinfo.io) # info localisation format json
publicip=$(echo $ipinfo | jq -r '.ip') # extraction des données , installer préalablement "jq"
ville=$(echo $ipinfo | jq -r '.city')
pays=$(echo $ipinfo | jq -r '.country')
cpuname=`cat /proc/cpuinfo |grep 'model name' | cut -d: -f2 | sed -n 1p`
iplink=`ip link show |grep -m 1 "2:" | awk '{print $2}' | cut -d: -f1`
echo "\033[0m\033[1;31m"
figlet "`hostname --fqdn`"
echo "\033[0m
\033[1;35m \033[1;37mHostname \033[1;35m= \033[1;32m`hostname`
\033[1;35m \033[1;37mWired IpV4 \033[1;35m= \033[1;32m`ip addr show $iplink | grep 'inet\b' | awk '{print $2}' | cut -d/ -f1`
\033[1;35m \033[1;37mWired IpV6 \033[1;35m= \033[1;32m`ip addr show $iplink | grep -E 'inet6' |grep -E 'scope link' | awk '{print $2}' | cut -d/ -f1`
\033[1;35m \033[1;37mKernel \033[1;35m= \033[1;32m`uname -r`
\033[1;35m \033[1;37mDebian \033[1;35m= \033[1;32m`cat /etc/debian_version`
\033[1;35m \033[1;37mUptime \033[1;35m= \033[1;32m`uptime | sed 's/.*up ([^,]*), .*/1/' | sed -e 's/^[ \t]*//'`
\033[1;35m \033[1;37mCPU \033[1;35m= \033[1;32m`echo $cpuname`
\033[1;35m \033[1;37mMemory Use \033[1;35m= \033[1;32m`free -m | awk 'NR==2{printf "%s/%sMB (%.2f%%)\n", $3,$2,$3*100/$2 }'`
\033[1;35m \033[1;37mUsername \033[1;35m= \033[1;32m`whoami`
\033[1;35m \033[1;37mSessions \033[1;35m= \033[1;32m`who | grep $USER | wc -l`
\033[1;35m \033[1;37mPublic IpV4 \033[1;35m= \033[1;32m`echo $publicip`
\033[1;35m \033[1;37mPublic IpV6 \033[1;35m= \033[1;32m`ip addr show $iplink | grep -m 1 'inet6\b' | awk '{print $2}' | cut -d/ -f1`
\033[0m"
df -h /
#curl fr.wttr.in/$ville?0
</code></pre></div></div>
<p>Effacer motd</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo rm /etc/motd
</code></pre></div></div>
<p>Déconnexion puis connexion</p>
<p><img src="/images/rc-raspberry.png" alt="" width="600px" /></p>
<h3 id="ssh--clés">SSH + Clés</h3>
<p><u>sur l'ordinateur de bureau</u><br />
Générer une paire de clé curve25519-sha256 (ECDH avec Curve25519 et SHA2) nommé xs35v2 pour une liaison SSH avec le serveur KVM.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen -t ed25519 -o -a 100 -f ~/.ssh/rpi3
</code></pre></div></div>
<p>Envoyer la clé publique sur le serveur KVM</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>scp ~/.ssh/rpi3.pub xsuser@192.168.0.45:/home/xsuser/
</code></pre></div></div>
<p><u>sur le Raspberry PI 3</u><br />
Copier le contenu de la clé publique dans /home/$USER/.ssh/authorized_keys</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cd ~
</code></pre></div></div>
<p>Sur le KVM ,créer un dossier .ssh</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir -p .ssh
cat /home/$USER/rpi3.pub &gt;&gt; /home/$USER/.ssh/authorized_keys
</code></pre></div></div>
<p>et donner les droits</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod 600 /home/$USER/.ssh/authorized_keys
</code></pre></div></div>
<p>effacer le fichier de la clé</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rm /home/$USER/xs35v2.pub
</code></pre></div></div>
<p>Modifier la configuration serveur SSH</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/ssh/sshd_config
</code></pre></div></div>
<p>Modifier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Port = 55029 # si souhaité sinon 22
PasswordAuthentication no
</code></pre></div></div>
<p>Relancer openSSH</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart ssh
</code></pre></div></div>
<p>Accès depuis le poste distant avec la clé privée</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -i ~/.ssh/rpi pi@192.168.0.41
</code></pre></div></div>
<h3 id="ipv6">IPV6</h3>
<p>Adresse inet6 <strong>fe80::107e:c702:47df:3f78</strong>/64 scope link</p>
<p>La carte nest joignable de linternet que par son adresse IPV6<br />
NextHop Freebox permet dattribuer une adresse IPV6</p>
<p>Prefixe : 2a01:e34:ee6a:b275:://64<br />
Next Hop: fe80::107e:c702:47df:3f78<br />
Passerelle IPV6 Box : fe80::224:d4ff:fea6:aa20</p>
<p>Modifier interface réseau raspbian</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/dhcpcd.conf # y ajouter ce qui suit
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>interface eth0
static ip6_address=2a01:e34:ee6a:b275::1/64
static routers=fe80::224:d4ff:fea6:aa20
static domain_name_servers=80.67.169.12 80.67.169.40 2a01:e00::1 2a01:e00::2
</code></pre></div></div>
<p>Redémarrez pour que les modifications prennent effet :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo reboot
</code></pre></div></div>
<p>Adresse publique IPV6 attribuée</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[...]
inet6 2a01:e34:ee6a:b275::1/64 scope global noprefixroute
[...]
</code></pre></div></div>
<h3 id="parefeu-iptables">Parefeu (iptables)</h3>
<p><img src="/images/parefeu-logo.png" alt="" /></p>
<p>iptables est normalement installé par défaut sur les serveurs.Dans le cas contraire</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install iptables # debian/ubuntu
</code></pre></div></div>
<p>Création script <strong>/usr/local/sbin/config_firewall</strong> pour le serveur</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/sh
###################
# IPv4 #
###################
# tout refuser par défaut
iptables -t filter -P INPUT DROP
iptables -t filter -P FORWARD DROP
iptables -t filter -P OUTPUT ACCEPT
# interface lo (loop) accessible
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# maintenir les connexions établies
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# accepter en entrée le ping (icmp), et les
# connexions sur les ports nécessaires.
iptables -A INPUT -p icmp --icmp-type echo-request -m conntrack --ctstate NEW -m limit --limit 1/s --limit-burst 1 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p udp --dport 22 -j ACCEPT
# accepter en sortie le ping, les requêtes HTTP(S), DNS,
# et les connexions sur les ports nécessaires.
iptables -A OUTPUT -p icmp --icmp-type echo-request -m conntrack --ctstate NEW -j ACCEPT
iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
#iptables -A OUTPUT -p tcp --dport xxxx -j ACCEPT
#iptables -A OUTPUT -p udp --dport xxxx -j ACCEPT
###################
# IPv6 #
###################
# tout refuser par défaut
ip6tables -t filter -P INPUT DROP
ip6tables -t filter -P FORWARD DROP
ip6tables -t filter -P OUTPUT ACCEPT
# interface lo (loop) accessible
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A OUTPUT -o lo -j ACCEPT
# maintenir les connexions établies
ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
ip6tables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# NDP pour toute interface de type broadcast
ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbour-solicitation -m hl --hl-eq 255 -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbour-advertisement -m hl --hl-eq 255 -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT
ip6tables -A OUTPUT -p icmpv6 --icmpv6-type neighbour-solicitation -j ACCEPT
ip6tables -A OUTPUT -p icmpv6 --icmpv6-type neighbour-advertisement -j ACCEPT
ip6tables -A OUTPUT -p icmpv6 --icmpv6-type router-solicitation -j ACCEPT
# accepter en entrée le ping (icmpv6), les
# connexions entrantes déjà établies et les connexions sur les ports nécessaires.
ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -m conntrack --ctstate NEW -m limit --limit 1/s --limit-burst 1 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 443 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT
ip6tables -A INPUT -p udp --dport 22 -j ACCEPT
# accepter en sortie le ping, les requêtes HTTP(S), DNS,
# et les connexions sur les ports nécessaires.
ip6tables -t filter -A OUTPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 80 -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 443 -j ACCEPT
ip6tables -A OUTPUT -p udp --dport 53 -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 53 -j ACCEPT
#ip6tables -A OUTPUT -p tcp --dport xxxx -j ACCEPT
#ip6tables -A OUTPUT -p udp --dport xxxx -j ACCEPT
</code></pre></div></div>
<p>Rendre exécutable et restreindre les droits sur le script</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chmod +x /usr/local/sbin/config_firewall
sudo chown root:root /usr/local/sbin/config_firewall
sudo chmod 740 /usr/local/sbin/config_firewall
</code></pre></div></div>
<p>Exécuter le script <strong>/usr/local/sbin/config_firewall</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /usr/local/sbin/config_firewall
</code></pre></div></div>
<p>Installer le paquet <strong>iptables-persistent</strong> pour définir des règles persistantes après un reboot.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install iptables-persistent
</code></pre></div></div>
<p>Pendant, linstallation du paquet, on vous est demande si vous souhaitez que les règles actuellement en cours dutilisation soient enregistrées dans le fichier .<br />
Valider Yes/Oui, pour IPV4 comme pour IPV6.</p>
<h2 id="horloge-externe-rtc-pour-raspberry-pi">Horloge externe (RTC) pour Raspberry Pi</h2>
<p>Module I2C RTC DS1307 (Real Time Clock)</p>
<p><img src="/images/rtc-ds1307.png" alt="" width="100" /></p>
<p>Liaisons entre le connecteur <strong>GPIO</strong> de la carte <strong>Raspberry Pi</strong> et le module <strong>I2C Real Time Clock DS1307 (5v) ou DS1338 (3.3v)</strong><br />
Le module utilisé est alimenté en 3.3v</p>
<table>
<thead>
<tr>
<th>RPI</th>
<th>Couleur</th>
<th>Module RTC</th>
<th>RPI désignation</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Rouge -&gt;</td>
<td>Vcc</td>
<td>+3.3v</td>
</tr>
<tr>
<td>3</td>
<td>Blanc -&gt;</td>
<td>SDA</td>
<td>GPIO02 (SDA1)</td>
</tr>
<tr>
<td>5</td>
<td>Jaune -&gt;</td>
<td>SCL</td>
<td>GPIO03 (SCL1)</td>
</tr>
<tr>
<td>9</td>
<td>Noir -&gt;</td>
<td>GND</td>
<td>GND</td>
</tr>
</tbody>
</table>
<p><strong>ATTENTION : Utilisation du bus i2c-2</strong></p>
<h3 id="i2c">i2c</h3>
<p>Activer le port i2c</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo raspi-config
</code></pre></div></div>
<p>Dans le menu <strong>Interfacing Options -&gt; P5 I2C</strong> il faut rendre actif le port i2c.<br />
Simple vérification</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dmesg |grep i2c
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> [ 2115.700449] i2c /dev entries driver
</code></pre></div></div>
<p>Nous allons vérifier que le module RTC est bien détecté<br />
Installation outil de test et vérification bus i2c</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt -y install i2c-tools python-smbus
</code></pre></div></div>
<p>Les bus détectés</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo i2cdetect -l
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>i2c-1 i2c bcm2835 I2C adapter I2C adapter
</code></pre></div></div>
<p>Le module est connecté sur le bus 1</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo i2cdetect -y 1
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
</code></pre></div></div>
<p>On voit que le RPi a détecté un composant à ladresse 0x68 qui daprès la <a href="https://www.sparkfun.com/datasheets/Components/DS1307.pdf">doc constructeur</a> est ladresse par défaut.Il faut un élément logiciel pour le contrôler (pilote).</p>
<h3 id="chargement-module-rtc-ds1307">Chargement Module RTC ds1307</h3>
<p>On va ajouter la gestion du module en éditant le fichier de configuration de boot.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /boot/config.txt
</code></pre></div></div>
<p>Auquel on va ajouter les lignes suivantes à la fin du fichier :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Module RTC
dtoverlay=i2c-rtc,ds1307
</code></pre></div></div>
<p>A ce stade, vous devez redémarrez votre système :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo reboot
</code></pre></div></div>
<p>Une fois le système de nouveau actif, éxécuter de nouveau:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo i2cdetect -y 1
</code></pre></div></div>
<p>Vous devriez observer si le prise en charge de lhorloge est effective en obtenant les caractères UU à ladresse 0X68</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
</code></pre></div></div>
<p>Il faut désactiver lhorloge qui émule lhorloge hardware <strong>fake hwclock</strong> avec les instructions suivantes</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt -y remove fake-hwclock
sudo update-rc.d -f fake-hwclock remove
</code></pre></div></div>
<p>Exécutez la commande suivante pour éditer le script RTC original.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /lib/udev/hwclock-set
</code></pre></div></div>
<p>Trouvez et commentez les trois lignes suivantes en plaçant # en tête de ligne</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>if [ -e /run/systemd/system ] ; then
exit 0
fi
</code></pre></div></div>
<p>Commenter avec #</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#if [ -e /run/systemd/system ] ; then
# exit 0
#fi
</code></pre></div></div>
<h3 id="synchronisation-temps-entre-module-pi-et-rtc">Synchronisation temps entre module Pi et RTC</h3>
<p>Maintenant que notre module RTC est branché et que Raspbian et le Raspberry Pi sont correctement configurés, nous devons synchroniser lheure avec notre module RTC. La raison en est que le temps fourni par un nouveau module RTC sera incorrect.</p>
<ol>
<li>
<p>Vous pouvez lire lheure directement à partir du module RTC en exécutant la commande suivante si vous lessayez maintenant, vous remarquerez quelle est actuellement très loin de notre temps réel actuel.</p>
<p>sudo hwclock -D -r</p>
</li>
<li>
<p>Maintenant avant daller de lavant et de synchroniser lheure correcte de notre Raspberry Pi à notre module RTC, nous devons exécuter la commande suivante pour nous assurer que lheure sur le Raspberry Pi est bien correcte, assurez-vous dêtre connecté à une connexion Wi-Fi ou Ethernet.</p>
<p>date</p>
</li>
<li>
<p>Si lheure affichée par la commande date est correcte, nous pouvons lancer la commande suivante sur votre Raspberry Pi. Cette commande permet décrire lheure entre le Raspberry Pi et le module RTC.</p>
<p>sudo hwclock -w</p>
</li>
<li>
<p>Maintenant, si vous lisez à nouveau lheure directement depuis le module RTC, vous remarquerez quelle a été modifiée à la même heure que celle à laquelle votre Raspberry Pi a été réglé. Vous ne devriez jamais avoir à réexécuter la commande précédente si vous avez une pile dans le module RTC.</p>
<p>sudo hwclock -r</p>
</li>
</ol>
<p>Vous disposez dun module RTC entièrement opérationnel qui maintient activement lheure de votre Raspberry Pi à lheure correcte, même hors connexion Internet.</p>
<hr />
<h2 id="ecran-tactile-résistif-tft-lcd-28-serial-spi">Ecran tactile (résistif) TFT LCD 2.8” serial SPI</h2>
<p><img src="/images/TFT-LCD-Display2.8-SPI.png" alt="" width="300" /></p>
<p>Raspberry PI/TouchScreen SPI TFT LCD 2.8p (ILI9341)</p>
<table>
<thead>
<tr>
<th>RPI</th>
<th>Aff.</th>
<th>Couleur</th>
<th>RPI désignation</th>
</tr>
</thead>
<tbody>
<tr>
<td>37</td>
<td>T_IRQ</td>
<td>Jaune</td>
<td>GPIO_GEN0 GPIO26</td>
</tr>
<tr>
<td> </td>
<td>T_D0 relié avec MISO</td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td>T_DIN relié avec MOSI</td>
<td> </td>
<td> </td>
</tr>
<tr>
<td>26</td>
<td>T_CS (CS1)</td>
<td>Blanc</td>
<td>SPI_CE1 GPIO7</td>
</tr>
<tr>
<td> </td>
<td>T_CLK relié avec SCLK</td>
<td> </td>
<td> </td>
</tr>
<tr>
<td>21</td>
<td>MISO</td>
<td>Jaune</td>
<td>SPI_MISO GPIO9</td>
</tr>
<tr>
<td>16</td>
<td>Led</td>
<td>Orange</td>
<td>GPIO_GEN4 GPIO23</td>
</tr>
<tr>
<td>23</td>
<td>SCLK</td>
<td>Violet</td>
<td>SPI_CLK GPIO11</td>
</tr>
<tr>
<td>19</td>
<td>MOSI</td>
<td>Bleu</td>
<td>SPI_MOSI GPIO10</td>
</tr>
<tr>
<td>18</td>
<td>D/C</td>
<td>Gris</td>
<td>GPIO_GEN5 GPIO24</td>
</tr>
<tr>
<td>22</td>
<td>Reset</td>
<td>Brun</td>
<td>GPIO25</td>
</tr>
<tr>
<td>24</td>
<td>CS</td>
<td>Vert</td>
<td>SPI_CE0 GPIO8</td>
</tr>
<tr>
<td>25</td>
<td>GND</td>
<td>Noir</td>
<td>- alimentation</td>
</tr>
<tr>
<td>17</td>
<td>+3.3v/Vcc</td>
<td>Rouge</td>
<td>+ alimentation</td>
</tr>
</tbody>
</table>
<p>Features:</p>
<ul>
<li>Compatible with Raspberry Pi B+ and B</li>
<li>Supports Raspbian Operating system</li>
<li>65K colors and 320x240 Pixel Resolution</li>
<li>Powered directly off Raspberry Pi</li>
<li>Display full GUI output / primary output</li>
<li>High Speed 48MHz SPI connection</li>
<li>25 Frames per second</li>
<li>Integrated ILI9341 TFT LCD Driver</li>
<li>Integrated 4-wire Resistive Touch Panel and XPT2046 Driver</li>
</ul>
<p>Activation du module SPI</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo nano /boot/config.txt
</code></pre></div></div>
<p>Enlever le commentaire (#) sur la ligne suivante du fichier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> dtparam=spi=on Redémarrer
sudo reboot
</code></pre></div></div>
<p>Vérifier chargement module SPI : <code class="language-plaintext highlighter-rouge">ls /dev</code><br />
SPI est actif si <code class="language-plaintext highlighter-rouge">/dev/spidev0.1</code> existe.</p>
<p>Il y a 2 méthodes pour laffichage:</p>
<ul>
<li>Utilisation de python
<ul>
<li><a href="https://behindthesciences.com/electronics/connecting-ili9341-SPI-TouchScreen-lcd-to-a-raspberry-pi-in-python/">Connecting ili9341 SPI TouchScreen LCD to a Raspberry Pi in Python</a></li>
</ul>
</li>
<li>Utilisation du module adafruit
<ul>
<li><a href="https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi/overview">Adafruit PiTFT - 2.8” Touchscreen Display for Raspberry Pi</a></li>
<li><a href="http://www.circuitbasics.com/raspberry-pi-touchscreen-calibration-screen-rotation/">Raspberry Pi Touchscreen Calibration and Screen Rotation</a></li>
</ul>
</li>
</ul>
<h3 id="utilisation-de-python">Utilisation de python</h3>
<p><em>La fiche technique de lili9341 SPI LCD est facilement disponible et vous pouvez lutiliser pour créer votre pilote python. On utilise le pilote écrit par Brian Lavery qui peut être téléchargé sur son <a href="https://github.com/BLavery/lib_tft24T">github</a>.</em></p>
<blockquote>
<p>ATTENTION ,si méthode A utilisé, il faut revenir à létat initial</p>
</blockquote>
<ul>
<li>Commenter les 2 lignes du fichier <strong>/etc/rc.local</strong> en ajoutant le caractère # en début de chaque ligne : <br />
<code class="language-plaintext highlighter-rouge">#exec /sbin/modprobe fbtft_device name=adafruit28 speed=48000000 rotate=90 verbose=1</code><br />
<code class="language-plaintext highlighter-rouge">#sudo sh -c "TERM=linux setterm -blank 0 &gt;/dev/tty0" # pour éviter le passage en veille</code></li>
<li>Oter les 2 commandes en fin de ligne du fichier <strong>/boot/cmdline.txt</strong> :<br />
<code class="language-plaintext highlighter-rouge">fbcon=map:10 fbcon=font:VGA8x8</code></li>
<li>Modifier le fichier <strong>/boot/config.txt</strong> , commenter la ligne (ajout # en début de ligne) :<br />
<code class="language-plaintext highlighter-rouge">#dtoverlay=ads7846,cs=1,penirq=26,xmin=200,xmax=3900,ymin=200,ymax=3900,xohms=60,pmax=255,swapxy</code><br />
Vérifier ou modifier le paramètre SPI: <code class="language-plaintext highlighter-rouge">dtparam=spi=on</code><br />
Ajouter au fichier <strong>/boot/config.txt</strong> : <code class="language-plaintext highlighter-rouge">dtoverlay=spi1-1cs</code> Ceci nactivera quune seule ligne CS , vous pouvez en avoir jusquà 3 sur le bus SPI1. Pour les options voir <strong>/boot/overlays/README</strong></li>
<li>Redémarrer : <code class="language-plaintext highlighter-rouge">sudo reboot</code></li>
</ul>
<p>Vérifier</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ls /dev/spi*
/dev/spidev0.0 /dev/spidev0.1 /dev/spidev1.0
</code></pre></div></div>
<h4 id="python-2-et-3--librairies">Python 2 et 3 + librairies</h4>
<p>Installer python 2 et 3, pip et les dépendances de pillow</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt -y install python-pip libjpeg62 libjpeg62-dev zlib1g-dev libfreetype6-dev liblcms1-dev python-dev python3-dev python-spidev python3-spidev
</code></pre></div></div>
<p><strong>Installer SPIDEV (py-spidev)</strong><br />
Téléchargerpy-spidev et le compiler prêt à lemploi :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt update
sudo apt upgrade
cd ~
#git clone https://github.com/doceme/py-spidev.git
git clone https://github.com/Gadgetoid/py-spidev.git
cd py-spidev
#make
#sudo make install
sudo python setup.py install
sudo python3 setup.py install
</code></pre></div></div>
<p><em>Vous devriez maintenant être prêt à communiquer avec des cartes dextension utilisant leurs propres bibliothèques (par exemple PiFace) ou dautres périphériques SPI (par exemple le <a href="https://www.raspberrypi-spy.co.uk/2013/10/analogue-sensors-on-the-raspberry-pi-using-an-mcp3008/">MCP3008 ADC</a>).</em></p>
<h4 id="ili9341-spi-raspberry-affichage-uniquement">ili9341 SPI Raspberry (affichage uniquement)</h4>
<p>Connexions ili9341 SPI Raspberry Pi</p>
<table>
<thead>
<tr>
<th>RPI Pin</th>
<th>Aff. ili9341</th>
<th>Couleur</th>
<th>RPI désignation</th>
</tr>
</thead>
<tbody>
<tr>
<td>37</td>
<td>PEN T_IRQ</td>
<td>Jaune</td>
<td>GPIO_GEN0 (GPIO26)</td>
</tr>
<tr>
<td> </td>
<td>T_D0 relié avec MISO</td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td>T_DIN relié avec MOSI</td>
<td> </td>
<td> </td>
</tr>
<tr>
<td>26</td>
<td>T_CS (CS1)</td>
<td>Blanc</td>
<td>SPI0_CE1 (GPIO7)</td>
</tr>
<tr>
<td> </td>
<td>T_CLK relié avec SCLK</td>
<td> </td>
<td> </td>
</tr>
<tr>
<td>21</td>
<td>SDO(MISO)</td>
<td>Jaune</td>
<td>SPI0_MISO (GPIO9)</td>
</tr>
<tr>
<td>16</td>
<td>Led</td>
<td>Orange</td>
<td>GPIO_GEN4 GPIO23</td>
</tr>
<tr>
<td>23</td>
<td>SCLK</td>
<td>Violet</td>
<td>SPI0_CLK (GPIO11)</td>
</tr>
<tr>
<td>19</td>
<td>SDI(MOSI)</td>
<td>Bleu</td>
<td>SPI0_MOSI (GPIO10)</td>
</tr>
<tr>
<td>18</td>
<td>D/C</td>
<td>Gris</td>
<td>GPIO_GEN5 (GPIO24)</td>
</tr>
<tr>
<td>22</td>
<td>Reset</td>
<td>Brun</td>
<td>(GPIO25)</td>
</tr>
<tr>
<td>24</td>
<td>CS</td>
<td>Vert</td>
<td>SPI_CE0 (GPIO8)</td>
</tr>
<tr>
<td>25</td>
<td>GND</td>
<td>Noir</td>
<td>- alimentation</td>
</tr>
<tr>
<td>17</td>
<td>+3.3v/Vcc</td>
<td>Rouge</td>
<td>+ alimentation</td>
</tr>
</tbody>
</table>
<p>Pour une utilisation sans “led” et “rst”:<br />
Relier rst (brun) de lafficheur TFT LCD ili9341 au +3.3V<br />
Relier led (orange) de lafficheur TFT LCD ili9341 au +3.3V</p>
<p><strong>Installer PIL Pillow</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo pip install Pillow
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[...]
Successfully installed Pillow-5.3.0
</code></pre></div></div>
<p><strong>Démonstration</strong><br />
Une fois que vous avez câblé lécran LCD ili9341 sur le Pi et que vous avez installé toutes les conditions préalables, cloner le fork du git de <a href="https://github.com/BLavery/lib_tft24T">Brian Lavery</a> dans votre espace utilisateur sur le Pi</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
git clone https://gitlab.cinay.xyz/spm/rpi-lib-tft-lcd.git
cd rpi-lib-tft-lcd
</code></pre></div></div>
<p>et exécutez la commande suivante :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python BTS_SPI_LCD_DEMO.py
</code></pre></div></div>
<p>Sil fonctionne correctement, vous verrez sur le terminal SSH :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Loading image...
Drawing image
Test a long para of text, auto-wrapped into screen lines.
show a font in giant letters
Loading image...
Drawing image
Test a long para of text, auto-wrapped into screen lines.
show a font in giant letters
</code></pre></div></div>
<p>Et sur lécran TFT LCD, une séquence de couleur, textes et images …<br />
Arrêt Ctrl + c</p>
<h4 id="ili9341-python-écran-tactile">ili9341 Python écran tactile</h4>
<p>Maintenant que vous avez un écran fonctionnel, il est temps de faire fonctionner lécran tactile.</p>
<p><em>Le Raspberry Pi a 2 bus SPI, SPI0 et SPI1. SPI0 peut prendre en charge 2 appareils, nous pouvons donc également connecter la partie tactile à SPI0. La partie Touch est connecté sur SPI0 avec le SPI0_CE1 (SPI0_CE0 est utilisé pour laffichage).</em></p>
<table>
<thead>
<tr>
<th>RPI Pin</th>
<th>Aff. ili9341</th>
<th>Couleur</th>
<th>RPI désignation</th>
</tr>
</thead>
<tbody>
<tr>
<td>37</td>
<td>T_IRQ</td>
<td>Jaune</td>
<td>GPIO_GEN0 (GPIO26)</td>
</tr>
<tr>
<td> </td>
<td>T_D0 relié avec MISO -&gt; SPI0_MISO (GPIO9)</td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td>T_DIN relié avec MOSI -&gt; SPI0_MOSI (GPIO10)</td>
<td> </td>
<td> </td>
</tr>
<tr>
<td>26</td>
<td>T_CS (CS1)</td>
<td>Blanc</td>
<td>SPI0_CE1 (GPIO7)</td>
</tr>
<tr>
<td> </td>
<td>T_CLK relié avec SCLK -&gt; SPI0_CLK (GPIO11)</td>
<td> </td>
<td> </td>
</tr>
</tbody>
</table>
<p>Lancer la calibration écran tactile</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~/rpi-lib-tft-lcd
python example-tft24T-touch-calibration.py
</code></pre></div></div>
<p>Suivez les instructions sur votre terminal SSH et vous aurez besoin de votre stylet pour cela…<br />
Une fois fait, vous verrez quelques chiffres détalonnage, notez-les. Vous devrez les entrer dans le fichier <strong>lib_tft24T.py</strong>.</p>
<h4 id="pygame">pygame</h4>
<p><a href="https://www.pygame.org/wiki/">https://www.pygame.org/wiki/</a></p>
<p>Installer python3-pip</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install python3-pip
</code></pre></div></div>
<p>Installer pygame</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install python3-pygame
</code></pre></div></div>
<p>Activer le module</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /sbin/modprobe fbtft_device name=adafruit28 speed=48000000 rotate=90 verbose=1
</code></pre></div></div>
<p>Test <strong>test1.py</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~/tutorials/pygamelcd/
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>'''
Created on Jul 12, 2014
@author: jeremyblythe
'''
import pygame
import os
from time import sleep
os.putenv('SDL_FBDEV', '/dev/fb1')
pygame.init()
lcd = pygame.display.set_mode((320, 240))
lcd.fill((255,0,0))
pygame.display.update()
sleep(1)
pygame.mouse.set_visible(False)
lcd.fill((0,0,0))
</code></pre></div></div>
<p>Exécution</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo python3 test1.py
</code></pre></div></div>
<h2 id="nginx-php7-mariadb">Nginx PHP7 MariaDB</h2>
<p><img src="/images/nginx-php7-mariadb1.png" alt="" /></p>
<h3 id="domaine-et-certificats">Domaine et certificats</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> _ _ _
___ _ _ ___ ___| |_| (_)_ __ ___ __ ___ _ ____
/ _ \| | | |/ _ \/ __| __| | | '_ \ / _ \ \ \/ / | | |_ /
| (_) | |_| | __/\__ \ |_| | | | | | __/_ &gt; &lt;| |_| |/ /
\___/ \__,_|\___||___/\__|_|_|_| |_|\___(_)_/\_\\__, /___|
|___/
</code></pre></div></div>
<p>Installation client acme</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
sudo -s # en mode super utilisateur
apt install netcat # prérequis
git clone https://github.com/Neilpang/acme.sh.git
cd acme.sh
./acme.sh --install # --nocron
cd ..
rm -rf acme.sh/
</code></pre></div></div>
<p>le client est installé dans /root/.acme.sh/</p>
<p>Utilisation clé et code secret avec API OVH</p>
<p><a href="https://eu.api.ovh.com/createApp/">OVH : Création de clé API application</a><br />
<a href="https://github.com/Neilpang/acme.sh/wiki/How-to-use-OVH-domain-api">How to use OVH domain api</a></p>
<p>En mode su , on exporte en local la clé et le code</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>export OVH_AK="REC23OMyBq2FZrLN"
export OVH_AS="32eqGDOrrF6b1Smj4kFgQdv1zX2DW7US"
</code></pre></div></div>
<p>Génération des certificats</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/root/.acme.sh/acme.sh --dns dns_ovh --issue --keylength ec-384 -d ouestline.xyz -d *.ouestline.xyz
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[mardi 20 novembre 2018, 21:18:22 (UTC+0100)] Your cert is in /root/.acme.sh/ouestline.xyz_ecc/ouestline.xyz.cer
[mardi 20 novembre 2018, 21:18:22 (UTC+0100)] Your cert key is in /root/.acme.sh/ouestline.xyz_ecc/ouestline.xyz.key
[mardi 20 novembre 2018, 21:18:22 (UTC+0100)] The intermediate CA cert is in /root/.acme.sh/ouestline.xyz_ecc/ca.cer
[mardi 20 novembre 2018, 21:18:22 (UTC+0100)] And the full chain certs is there: /root/.acme.sh/ouestline.xyz_ecc/fullchain.cer
</code></pre></div></div>
<p>Créer des liens</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo ln -s /root/.acme.sh/ouestline.xyz_ecc/fullchain.cer /etc/ssl/private/ouestline.xyz.fullchain.cer.pem;
sudo ln -s /root/.acme.sh/ouestline.xyz_ecc/ouestline.xyz.key /etc/ssl/private/ouestline.xyz.key.pem;
</code></pre></div></div>
<p>Le fichier de configuration <strong>/etc/nginx/conf.d/default.conf</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
listen 80;
listen [::]:80;
## redirect http to https ##
server_name ouestline.xyz *.ouestline.xyz;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name ouestline.xyz;
root /var/www/ ;
ssl_certificate /etc/ssl/private/ouestline.xyz.fullchain.cer.pem;
ssl_certificate_key /etc/ssl/private/ouestline.xyz.key.pem;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
# As suggested by https://cipherli.st/
ssl_ecdh_curve secp384r1;
ssl_prefer_server_ciphers on;
# Ciphers with intermediate compatibility
#----------------------------------------
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&amp;openssl=1.0.1t&amp;hsts=yes&amp;profile=intermediate
#ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#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';
# Ciphers with modern compatibility
#---------------------------------
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&amp;openssl=1.0.1t&amp;hsts=yes&amp;profile=modern
# Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android &lt; 5.0, Internet Explorer &lt; 10, ...)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS13+AESGCM+AES128:EECDH+AESGCM:EECDH+CHACHA20:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
# Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners
# https://wiki.mozilla.org/Security/Guidelines/Web_Security
# https://observatory.mozilla.org/
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header Content-Security-Policy "upgrade-insecure-requests";
add_header Content-Security-Policy-Report-Only "default-src https: data: 'unsafe-inline' 'unsafe-eval'";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header X-Frame-Options "SAMEORIGIN";
index index.php index.html;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.2-fpm.sock; # PHP7.2
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
access_log /var/log/nginx/ouestline.xyz-access.log;
error_log /var/log/nginx/ouestline.xyz-error.log;
}
</code></pre></div></div>
<p>Vérifier et relancer nginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nginx -t
sudo systemctl restart nginx
</code></pre></div></div>
<p>Lien https://ouestline.xyz</p>
<p>Vérifier la validité TLSV1.3 sur le navigateur <br />
<img src="/images/tlsv1.3.png" alt="" width="400px" /></p>
</div>
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2018-11-28T00:00:00+01:00"><!-- start custom article footer snippet -->
<!-- end custom article footer snippet -->
<!--
<div align="right"><a type="application/rss+xml" href="/feed.xml" title="S'abonner"><i class="fa fa-rss fa-2x"></i></a>
&emsp;</div>
-->
</footer>
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2018/11/23/xeuyakzas.xyz.html">xeuyakzas.xyz (VPS austria)</a></div><div class="next"><span>SUIVANT</span><a href="/2018/12/21/vps591606_debian_9_yunohost_cinay.xyz.html">vps591606 Debian 9 - Yunohost - cinay.xyz (INACTIF)</a></div></div></div>
</div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
$(function() {
var $this ,$scroll;
var $articleContent = $('.js-article-content');
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var scroll = hasSidebar ? '.js-page-main' : 'html, body';
$scroll = $(scroll);
$articleContent.find('.highlight').each(function() {
$this = $(this);
$this.attr('data-lang', $this.find('code').attr('data-lang'));
});
$articleContent.find('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').each(function() {
$this = $(this);
$this.append($('<a class="anchor d-print-none" aria-hidden="true"></a>').html('<i class="fas fa-anchor"></i>'));
});
$articleContent.on('click', '.anchor', function() {
$scroll.scrollToAnchor('#' + $(this).parent().attr('id'), 400);
});
});
});
})();
</script>
</div><section class="page__comments d-print-none"></section></article><!-- start custom main bottom snippet -->
<!-- end custom main bottom snippet -->
</div>
</div></div></div></div>
</div><script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $body = $('body'), $window = $(window);
var $pageRoot = $('.js-page-root'), $pageMain = $('.js-page-main');
var activeCount = 0;
function modal(options) {
var $root = this, visible, onChange, hideWhenWindowScroll = false;
var scrollTop;
function setOptions(options) {
var _options = options || {};
visible = _options.initialVisible === undefined ? false : show;
onChange = _options.onChange;
hideWhenWindowScroll = _options.hideWhenWindowScroll;
}
function init() {
setState(visible);
}
function setState(isShow) {
if (isShow === visible) {
return;
}
visible = isShow;
if (visible) {
activeCount++;
scrollTop = $(window).scrollTop() || $pageMain.scrollTop();
$root.addClass('modal--show');
$pageMain.scrollTop(scrollTop);
activeCount === 1 && ($pageRoot.addClass('show-modal'), $body.addClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.on('scroll', hide);
$window.on('keyup', handleKeyup);
} else {
activeCount > 0 && activeCount--;
$root.removeClass('modal--show');
$window.scrollTop(scrollTop);
activeCount === 0 && ($pageRoot.removeClass('show-modal'), $body.removeClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.off('scroll', hide);
$window.off('keyup', handleKeyup);
}
onChange && onChange(visible);
}
function show() {
setState(true);
}
function hide() {
setState(false);
}
function handleKeyup(e) {
// Char Code: 27 ESC
if (e.which === 27) {
hide();
}
}
setOptions(options);
init();
return {
show: show,
hide: hide,
$el: $root
};
}
$.fn.modal = modal;
});
})();
</script><div class="modal modal--overflow page__search-modal d-print-none js-page-search-modal"><script>
(function () {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
// search panel
var search = (window.search || (window.search = {}));
var useDefaultSearchBox = window.useDefaultSearchBox === undefined ?
true : window.useDefaultSearchBox ;
var $searchModal = $('.js-page-search-modal');
var $searchToggle = $('.js-search-toggle');
var searchModal = $searchModal.modal({ onChange: handleModalChange, hideWhenWindowScroll: true });
var modalVisible = false;
search.searchModal = searchModal;
var $searchBox = null;
var $searchInput = null;
var $searchClear = null;
function getModalVisible() {
return modalVisible;
}
search.getModalVisible = getModalVisible;
function handleModalChange(visible) {
modalVisible = visible;
if (visible) {
search.onShow && search.onShow();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].focus();
} else {
search.onShow && search.onHide();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].blur();
setTimeout(function() {
useDefaultSearchBox && ($searchInput.val(''), $searchBox.removeClass('not-empty'));
search.clear && search.clear();
window.pageAsideAffix && window.pageAsideAffix.refresh();
}, 400);
}
}
$searchToggle.on('click', function() {
modalVisible ? searchModal.hide() : searchModal.show();
});
// Char Code: 83 S, 191 /
$(window).on('keyup', function(e) {
if (!modalVisible && !window.isFormElement(e.target || e.srcElement) && (e.which === 83 || e.which === 191)) {
modalVisible || searchModal.show();
}
});
if (useDefaultSearchBox) {
$searchBox = $('.js-search-box');
$searchInput = $searchBox.children('input');
$searchClear = $searchBox.children('.js-icon-clear');
search.getSearchInput = function() {
return $searchInput.get(0);
};
search.getVal = function() {
return $searchInput.val();
};
search.setVal = function(val) {
$searchInput.val(val);
};
$searchInput.on('focus', function() {
$(this).addClass('focus');
});
$searchInput.on('blur', function() {
$(this).removeClass('focus');
});
$searchInput.on('input', window.throttle(function() {
var val = $(this).val();
if (val === '' || typeof val !== 'string') {
search.clear && search.clear();
} else {
$searchBox.addClass('not-empty');
search.onInputNotEmpty && search.onInputNotEmpty(val);
}
}, 400));
$searchClear.on('click', function() {
$searchInput.val(''); $searchBox.removeClass('not-empty');
search.clear && search.clear();
});
}
});
})();
</script><div class="search search--dark">
<div class="main">
<div class="search__header">Recherche</div>
<div class="search-bar">
<div class="search-box js-search-box">
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
<input id="search-input" type="text" />
<div class="search-box__icon-clear js-icon-clear">
<a><i class="fas fa-times"></i></a>
</div>
</div>
<button class="button button--theme-dark button--pill search__cancel js-search-toggle">
Annuler</button>
</div>
<div id="results-container" class="search-result js-search-result"></div>
</div>
</div>
<!-- Script pointing to search-script.js -->
<script>/*!
* Simple-Jekyll-Search
* Copyright 2015-2020, Christian Fei
* Licensed under the MIT License.
*/
(function(){
'use strict'
var _$Templater_7 = {
compile: compile,
setOptions: setOptions
}
const options = {}
options.pattern = /\{(.*?)\}/g
options.template = ''
options.middleware = function () {}
function setOptions (_options) {
options.pattern = _options.pattern || options.pattern
options.template = _options.template || options.template
if (typeof _options.middleware === 'function') {
options.middleware = _options.middleware
}
}
function compile (data) {
return options.template.replace(options.pattern, function (match, prop) {
const value = options.middleware(prop, data[prop], options.template)
if (typeof value !== 'undefined') {
return value
}
return data[prop] || match
})
}
'use strict';
function fuzzysearch (needle, haystack) {
var tlen = haystack.length;
var qlen = needle.length;
if (qlen > tlen) {
return false;
}
if (qlen === tlen) {
return needle === haystack;
}
outer: for (var i = 0, j = 0; i < qlen; i++) {
var nch = needle.charCodeAt(i);
while (j < tlen) {
if (haystack.charCodeAt(j++) === nch) {
continue outer;
}
}
return false;
}
return true;
}
var _$fuzzysearch_1 = fuzzysearch;
'use strict'
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
function FuzzySearchStrategy () {
this.matches = function (string, crit) {
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
}
}
'use strict'
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
function LiteralSearchStrategy () {
this.matches = function (str, crit) {
if (!str) return false
str = str.trim().toLowerCase()
crit = crit.trim().toLowerCase()
return crit.split(' ').filter(function (word) {
return str.indexOf(word) >= 0
}).length === crit.split(' ').length
}
}
'use strict'
var _$Repository_4 = {
put: put,
clear: clear,
search: search,
setOptions: __setOptions_4
}
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
function NoSort () {
return 0
}
const data = []
let opt = {}
opt.fuzzy = false
opt.limit = 10
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = NoSort
opt.exclude = []
function put (data) {
if (isObject(data)) {
return addObject(data)
}
if (isArray(data)) {
return addArray(data)
}
return undefined
}
function clear () {
data.length = 0
return data
}
function isObject (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
}
function isArray (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
}
function addObject (_data) {
data.push(_data)
return data
}
function addArray (_data) {
const added = []
clear()
for (let i = 0, len = _data.length; i < len; i++) {
if (isObject(_data[i])) {
added.push(addObject(_data[i]))
}
}
return added
}
function search (crit) {
if (!crit) {
return []
}
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
}
function __setOptions_4 (_opt) {
opt = _opt || {}
opt.fuzzy = _opt.fuzzy || false
opt.limit = _opt.limit || 10
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = _opt.sort || NoSort
opt.exclude = _opt.exclude || []
}
function findMatches (data, crit, strategy, opt) {
const matches = []
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
const match = findMatchesInObject(data[i], crit, strategy, opt)
if (match) {
matches.push(match)
}
}
return matches
}
function findMatchesInObject (obj, crit, strategy, opt) {
for (const key in obj) {
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
return obj
}
}
}
function isExcluded (term, excludedTerms) {
for (let i = 0, len = excludedTerms.length; i < len; i++) {
const excludedTerm = excludedTerms[i]
if (new RegExp(excludedTerm).test(term)) {
return true
}
}
return false
}
/* globals ActiveXObject:false */
'use strict'
var _$JSONLoader_2 = {
load: load
}
function load (location, callback) {
const xhr = getXHR()
xhr.open('GET', location, true)
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
xhr.send()
}
function createStateChangeListener (xhr, callback) {
return function () {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
callback(null, JSON.parse(xhr.responseText))
} catch (err) {
callback(err, null)
}
}
}
}
function getXHR () {
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
}
'use strict'
var _$OptionsValidator_3 = function OptionsValidator (params) {
if (!validateParams(params)) {
throw new Error('-- OptionsValidator: required options missing')
}
if (!(this instanceof OptionsValidator)) {
return new OptionsValidator(params)
}
const requiredOptions = params.required
this.getRequiredOptions = function () {
return requiredOptions
}
this.validate = function (parameters) {
const errors = []
requiredOptions.forEach(function (requiredOptionName) {
if (typeof parameters[requiredOptionName] === 'undefined') {
errors.push(requiredOptionName)
}
})
return errors
}
function validateParams (params) {
if (!params) {
return false
}
return typeof params.required !== 'undefined' && params.required instanceof Array
}
}
'use strict'
var _$utils_9 = {
merge: merge,
isJSON: isJSON
}
function merge (defaultParams, mergeParams) {
const mergedOptions = {}
for (const option in defaultParams) {
mergedOptions[option] = defaultParams[option]
if (typeof mergeParams[option] !== 'undefined') {
mergedOptions[option] = mergeParams[option]
}
}
return mergedOptions
}
function isJSON (json) {
try {
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
return true
}
return false
} catch (err) {
return false
}
}
var _$src_8 = {};
(function (window) {
'use strict'
let options = {
searchInput: null,
resultsContainer: null,
json: [],
success: Function.prototype,
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
templateMiddleware: Function.prototype,
sortMiddleware: function () {
return 0
},
noResultsText: 'No results found',
limit: 10,
fuzzy: false,
debounceTime: null,
exclude: []
}
let debounceTimerHandle
const debounce = function (func, delayMillis) {
if (delayMillis) {
clearTimeout(debounceTimerHandle)
debounceTimerHandle = setTimeout(func, delayMillis)
} else {
func.call()
}
}
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
/* removed: const _$Templater_7 = require('./Templater') */;
/* removed: const _$Repository_4 = require('./Repository') */;
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
const optionsValidator = _$OptionsValidator_3({
required: requiredOptions
})
/* removed: const _$utils_9 = require('./utils') */;
window.SimpleJekyllSearch = function (_options) {
const errors = optionsValidator.validate(_options)
if (errors.length > 0) {
throwError('You must specify the following required options: ' + requiredOptions)
}
options = _$utils_9.merge(options, _options)
_$Templater_7.setOptions({
template: options.searchResultTemplate,
middleware: options.templateMiddleware
})
_$Repository_4.setOptions({
fuzzy: options.fuzzy,
limit: options.limit,
sort: options.sortMiddleware,
exclude: options.exclude
})
if (_$utils_9.isJSON(options.json)) {
initWithJSON(options.json)
} else {
initWithURL(options.json)
}
const rv = {
search: search
}
typeof options.success === 'function' && options.success.call(rv)
return rv
}
function initWithJSON (json) {
_$Repository_4.put(json)
registerInput()
}
function initWithURL (url) {
_$JSONLoader_2.load(url, function (err, json) {
if (err) {
throwError('failed to get JSON (' + url + ')')
}
initWithJSON(json)
})
}
function emptyResultsContainer () {
options.resultsContainer.innerHTML = ''
}
function appendToResultsContainer (text) {
options.resultsContainer.innerHTML += text
}
function registerInput () {
options.searchInput.addEventListener('input', function (e) {
if (isWhitelistedKey(e.which)) {
emptyResultsContainer()
debounce(function () { search(e.target.value) }, options.debounceTime)
}
})
}
function search (query) {
if (isValidQuery(query)) {
emptyResultsContainer()
render(_$Repository_4.search(query), query)
}
}
function render (results, query) {
const len = results.length
if (len === 0) {
return appendToResultsContainer(options.noResultsText)
}
for (let i = 0; i < len; i++) {
results[i].query = query
appendToResultsContainer(_$Templater_7.compile(results[i]))
}
}
function isValidQuery (query) {
return query && query.length > 0
}
function isWhitelistedKey (key) {
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
}
function throwError (message) {
throw new Error('SimpleJekyllSearch --- ' + message)
}
})(window)
}());
</script>
<!-- Configuration -->
<script>
SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
noResultsText: '<p>Aucun résultat!</p>',
json: '/search.json',
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{title}</a>&nbsp;(Création {create})</li>'
})
</script>
</div></div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function scrollToAnchor(anchor, duration, callback) {
var $root = this;
$root.animate({ scrollTop: $(anchor).position().top }, duration, function() {
window.history.replaceState(null, '', window.location.href.split('#')[0] + anchor);
callback && callback();
});
}
$.fn.scrollToAnchor = scrollToAnchor;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function affix(options) {
var $root = this, $window = $(window), $scrollTarget, $scroll,
offsetBottom = 0, scrollTarget = window, scroll = window.document, disabled = false, isOverallScroller = true,
rootTop, rootLeft, rootHeight, scrollBottom, rootBottomTop,
hasInit = false, curState;
function setOptions(options) {
var _options = options || {};
_options.offsetBottom && (offsetBottom = _options.offsetBottom);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroll && (scroll = _options.scroll);
_options.disabled !== undefined && (disabled = _options.disabled);
$scrollTarget = $(scrollTarget);
isOverallScroller = window.isOverallScroller($scrollTarget[0]);
$scroll = $(scroll);
}
function preCalc() {
top();
rootHeight = $root.outerHeight();
rootTop = $root.offset().top + (isOverallScroller ? 0 : $scrollTarget.scrollTop());
rootLeft = $root.offset().left;
}
function calc(needPreCalc) {
needPreCalc && preCalc();
scrollBottom = $scroll.outerHeight() - offsetBottom - rootHeight;
rootBottomTop = scrollBottom - rootTop;
}
function top() {
if (curState !== 'top') {
$root.removeClass('fixed').css({
left: 0,
top: 0
});
curState = 'top';
}
}
function fixed() {
if (curState !== 'fixed') {
$root.addClass('fixed').css({
left: rootLeft + 'px',
top: 0
});
curState = 'fixed';
}
}
function bottom() {
if (curState !== 'bottom') {
$root.removeClass('fixed').css({
left: 0,
top: rootBottomTop + 'px'
});
curState = 'bottom';
}
}
function setState() {
var scrollTop = $scrollTarget.scrollTop();
if (scrollTop >= rootTop && scrollTop <= scrollBottom) {
fixed();
} else if (scrollTop < rootTop) {
top();
} else {
bottom();
}
}
function init() {
if(!hasInit) {
var interval, timeout;
calc(true); setState();
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState();
});
$window.on('resize', function() {
disabled || (calc(true), setState());
});
hasInit = true;
}
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions,
refresh: function() {
calc(true, { animation: false }); setState();
}
};
}
$.fn.affix = affix;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function toc(options) {
var $root = this, $window = $(window), $scrollTarget, $scroller, $tocUl = $('<ul class="toc toc--ellipsis"></ul>'), $tocLi, $headings, $activeLast, $activeCur,
selectors = 'h1,h2,h3', container = 'body', scrollTarget = window, scroller = 'html, body', disabled = false,
headingsPos, scrolling = false, hasRendered = false, hasInit = false;
function setOptions(options) {
var _options = options || {};
_options.selectors && (selectors = _options.selectors);
_options.container && (container = _options.container);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroller && (scroller = _options.scroller);
_options.disabled !== undefined && (disabled = _options.disabled);
$headings = $(container).find(selectors).filter('[id]');
$scrollTarget = $(scrollTarget);
$scroller = $(scroller);
}
function calc() {
headingsPos = [];
$headings.each(function() {
headingsPos.push(Math.floor($(this).position().top));
});
}
function setState(element, disabled) {
var scrollTop = $scrollTarget.scrollTop(), i;
if (disabled || !headingsPos || headingsPos.length < 1) { return; }
if (element) {
$activeCur = element;
} else {
for (i = 0; i < headingsPos.length; i++) {
if (scrollTop >= headingsPos[i]) {
$activeCur = $tocLi.eq(i);
} else {
$activeCur || ($activeCur = $tocLi.eq(i));
break;
}
}
}
$activeLast && $activeLast.removeClass('active');
($activeLast = $activeCur).addClass('active');
}
function render() {
if(!hasRendered) {
$root.append($tocUl);
$headings.each(function() {
var $this = $(this);
$tocUl.append($('<li></li>').addClass('toc-' + $this.prop('tagName').toLowerCase())
.append($('<a></a>').text($this.text()).attr('href', '#' + $this.prop('id'))));
});
$tocLi = $tocUl.children('li');
$tocUl.on('click', 'a', function(e) {
e.preventDefault();
var $this = $(this);
scrolling = true;
setState($this.parent());
$scroller.scrollToAnchor($this.attr('href'), 400, function() {
scrolling = false;
});
});
}
hasRendered = true;
}
function init() {
var interval, timeout;
if(!hasInit) {
render(); calc(); setState(null, scrolling);
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState(null, scrolling);
});
$window.on('resize', window.throttle(function() {
if (!disabled) {
render(); calc(); setState(null, scrolling);
}
}, 100));
}
hasInit = true;
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions
};
}
$.fn.toc = toc;
});
})();
/*(function () {
})();*/
</script><script>
/* toc must before affix, since affix need to konw toc' height. */(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
var TOC_SELECTOR = window.TEXT_VARIABLES.site.toc.selectors;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window);
var $articleContent = $('.js-article-content');
var $tocRoot = $('.js-toc-root'), $col2 = $('.js-col-aside');
var toc;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var hasToc = $articleContent.find(TOC_SELECTOR).length > 0;
function disabled() {
return $col2.css('display') === 'none' || !hasToc;
}
tocDisabled = disabled();
toc = $tocRoot.toc({
selectors: TOC_SELECTOR,
container: $articleContent,
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
tocDisabled = disabled();
toc && toc.setOptions({
disabled: tocDisabled
});
}, 100));
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window), $pageFooter = $('.js-page-footer');
var $pageAside = $('.js-page-aside');
var affix;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
affix = $pageAside.affix({
offsetBottom: $pageFooter.outerHeight(),
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
scroll: hasSidebar ? $('.js-page-main').children() : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
affix && affix.setOptions({
disabled: tocDisabled
});
}, 100));
window.pageAsideAffix = affix;
});
})();
</script><!---->
</div>
<script>(function () {
var $root = document.getElementsByClassName('root')[0];
if (window.hasEvent('touchstart')) {
$root.dataset.isTouch = true;
document.addEventListener('touchstart', function(){}, false);
}
})();
</script>
</body>
</html>