STF - Read ME

Abstract

STF is an helper, intending to slow or stop smoking.

Principe

En tant que fumeur j'ai pu constater que vouloir se passer de cigarette est plus facile à certain moments.

Certaines sources prétendent que s'abstenir momentanément de fumer, provoque un état de stress qui vous incitera à plus fumer par la suite. En réalité, cet état de stress apparaît parfois, et des fois pas... comment identifier ces moments ?

Une première version1 utilisait les "chaînes de Markov", c'est à dire que chaque évaluation tient compte des deux événements précédents (todo: détailler). La faire évoluer impliquait qu'il fallait considérer plus que deux événements, l'aurait rendue délicate à configurer.

La deuxième version utilise un "loi"2 établie par des tabacologues, qui dit que la concentration du sang en nicotine (qui augmente à chaque consommation), est divisée par 2 toutes les 2 heures. Et qu'elle est nulle au bout de 8 heures.

L'idée est donc qu'à partir de paramètres choisis (délais d'attente), le système calcule l'évolution du taux de nicotine dans le sang, pour déterminer en fonction d'un seuil de stress , un délai d'attente acceptable.

Présentation

(todo: screenshots)

Utilisation

...(todo)

1

non publiée. Apple est très pointilleux sur certains sujets.

2

Je ne la confirme pas. En réalité on dit la même chose sur l'alcool, et on sait que nous ne sommes pas tous égaux sur le sujet. Je pencherais plutôt pour une diminution linéaire, associée à une division par un facteur différent. Intuitivement la diminution devrait être linéaire, mais l'organisme mobilise plus de moyens pour éliminer des produits indésirables, s'ils sont en plus grande quantité. L'application a également vocation de recherche, et des réglages seront proposés.

STF - Read ME

Abstract

STF is an helper, intending to slow or stop smoking.

Principe

En tant que fumeur j'ai pu constater que vouloir se passer de cigarette est plus facile à certain moments.

Certaines sources prétendent que s'abstenir momentanément de fumer, provoque un état de stress qui vous incitera à plus fumer par la suite. En réalité, cet état de stress apparaît parfois, et des fois pas... comment identifier ces moments ?

Une première version1 utilisait les "chaînes de Markov", c'est à dire que chaque évaluation tient compte des deux événements précédents (todo: détailler). La faire évoluer impliquait qu'il fallait considérer plus que deux événements, l'aurait rendue délicate à configurer.

La deuxième version utilise un "loi"2 établie par des tabacologues, qui dit que la concentration du sang en nicotine (qui augmente à chaque consommation), est divisée par 2 toutes les 2 heures. Et qu'elle est nulle au bout de 8 heures.

L'idée est donc qu'à partir de paramètres choisis (délais d'attente), le système calcule l'évolution du taux de nicotine dans le sang, pour déterminer en fonction d'un seuil de stress , un délai d'attente acceptable.

Présentation

(todo: screenshots)

Utilisation

...(todo)

1

non publiée. Apple est très pointilleux sur certains sujets.

2

Je ne la confirme pas. En réalité on dit la même chose sur l'alcool, et on sait que nous ne sommes pas tous égaux sur le sujet. Je pencherais plutôt pour une diminution linéaire, associée à une division par un facteur différent. Intuitivement la diminution devrait être linéaire, mais l'organisme mobilise plus de moyens pour éliminer des produits indésirables, s'ils sont en plus grande quantité. L'application a également vocation de recherche, et des réglages seront proposés.

S.T.F. - VERSION LOG

Features Resume

  • The display shows 3 kinds of TextFields:

    • "Entries" TextFields, defined by Users, are shown on Top of the GraphView, their horizontal repartition reflects their Date value,
    • "Date" TextFields, build sequentially by the app, are shown on Bottom of the GraphView, their are shown as abscissae marks; showed as two-digits values;
    • a "Time" TextFields, vertically centered, shows the Current Time, moving to to right as the Current Time increase; in addition two other field show the recommended and expected Times; showed as two-digits+two-digits values (hh:mm); forced to the 24h display style;
    • all of these are dynamically built at runtime;
  • when too many Entries make that some TextField do overleap, some are "Tabbed" at Left : they are vertically aligned (same X position), not considering their Date property, (todo: swipe feature => do tab at Right / do untab at Left)

  • Entries are made when double-clicking any where, and setting a time is the popup-view; if double-clicking in an existing Entry TextField, it makes it to be Edited (a new value will replace the previous and the TextField is moved accordingly to this value); Entry can also be removed

  • as soon as an Entry exists, a Graphic shows Levels evolment in 3 colors, tied to your real nicotine Level and eveluated using two thresholds: Red if the level is highter than the "maximum" level, Green if lower than the "accepted" level, Orange between. You may set these two level by yourself.

    This is so showing an evaluation for the opportunity to create a new Entry; you are supposed to wait the current Time to stand over an orange zone. The goal is to wait a green zone and change as it comes easier. The orange zone is a tolerance.

  • Dates are created as necessary, ensuring to cover the all Entries TextField, as the current Time TextField, and the time where the Graphic turns to green

  • if creating an Entry Fields an overleap occurs, a zoom factor is applied; if all Entries for a day are not contained in the main View, some Date Fields are removed, and some Entry Fields are "tabbed", meaning that a "Tab Zone" is activated, these Entry Fields will be vertically placed in, and all objects in the remaining zone (whole view zone minus "Tab Zone") are placed differently,

  • "Entries" can be added in any order, and sorted (it's rarelly usefull do do that)

  • "Entries" are persistent

  • "Entries" dates are saved in the UTC format, and displayed in the locale format; 24h display (vs AM/PM) is forced, to avoid spoiling place of the display.

Status:

INCOMPLETE

RoadMap

  • add Entries (using double-tap)

  • can change the display range (automatic, checking for Entries overlapping)

  • colors for Entry Fields (and the line to bottom) according to the level at creation Time; needs to store levelBefore/levelNow

  • present a View for Level Settings: "maximum" level and "accepted" level,

    • design the view
    • add the choice for the Starting Day Time (means that a "Day" starts from this Time to the same Time 24h later) (ok but not used yet)
  • use "User" identity (ask at launch?)

    • use userID to save and Load (local database)
    • can work with/without userID
    • when switching from without to with identity, ask for converting non-user Entries
    • display this view
    • if use userID, display option (checkbox) to ask for an UserID at launch, or change explicitly from this view the "set user" feature is disabled for now; data are expected to remain usable within the next version.
  • synchronize database ("replicator"); add user ID in the DocID first;

    • use System Prefs for the Server Settings (address/credential/password)
    • can sync
    • present the feature to the User (where?) the "synchronize" feature is disabled for now; works but need to precise the strategy
  • make entries as editable (ok, using double-tap inside an Entry)

    • update Levels when the Entry is not the last one
  • Remove action

    • remove the first Entry (ok, using double-tap inside an Entry)
    • remove the last Entry
    • remove an Entry when it's alone
    • update Levels when the Entry is not the last one (toto: check)
  • add title to Digicode, for Add VS Moddify/Remove

    • use a different View

RoadMap (future version)

  • swipe to change the view per day?

    • better do this: draw the whole current Day (curve) in a scrollView, synchronize scroll with tab/untab Entries/Dates
  • display Tips to help waiting some durations (e.g. sweep one room = 3mn, put away the dishes, ..). can sort these with durations. can ask for user how much such a duration was for him.

  • currently, color for Entries TextFields is only for border -> try to apply to background (with alpha?)?

    • check applying a shadow on TextField?
  • do group the entries (e.g. by 5) in the tabzone!

    • needs to map (time->xPosition) the last tabbed Entry

    • wait for the scroll view


Issues

  • CHECK : if all the Entries are tabbed, what happens??? (zoom may crash, firstUntabbed() may crash)

  • TODO: should forbid to add Entries post to the CurrentDate

    • sure of this? this can be useful,... perhaps put an alert?

    • better?: allow with limit (e.g. 4h or 6h ...?)

  • NOTE: if two Entry, while the first is tabbed and near 24h before the Current Date and, the second is post the CurrentDate, the Current Date doesn't display; if untab the first Entry this would display too many Dates Fields... but if the first is from the same Day, do build Date TextFields solved (toto: check)

    • this should be solved if using a scrollView
  • change text when the Devise is vertical ("portrait") : 01, 02, 03...

    • this will avoid resizing with too much tabbing because of too much overlapping;

    • this is an useful information too,

    • needs to track this information in Entries (beware of Insert mode); needs also to fix the time for Day Start (after midnight)

  • ISSUE: dates are never removed, only tabbed 1) remove Entries at left: use a parameter (e.g. 24h) 2) if Date prior to this parameter minus one remove it

  • (ISSUE, check: is this also for Entries?)

  • ISSUE: if the Current Time is just after midnigh, and a new Entry is set manually to just before, it's stored with the day of the Current Time (i.e. 24h after the expected Time)

    • compare the difference with the 2 possibilities?

Change Log

Here is the list of the newest versions in Descending Order, beginning from the latest version.

#0.39

  • connected the Settings View,
  • get the Settings, can modify, save, (todo: apply)
  • fix: Times as computed to be "green" often appeared in "orange", due to rounding values as minutes,
  • strong issue: system icons for the Settings (and so on) don't appear on iPhone -> due to iOS version -> designed all icons, FIXED
  • strong issue: date conversions (Date<->String) fail if User Settings want the Time to be displayed as 12h (e.g. "14:44:30" VS "2:44:30 PM"), could crash, FIXED

#0.38

  • refactored Dates functions from DataTextFields to DatesTextFields,
  • simplified Green/Blue TextFields access,
  • simplified Dates TextFields builds,
  • fixed a wrong TextFields size at launch
  • fix a wrong Day Date when a new Entry and the Current Time are in opposite part of midnight (not check)

#0.37

  • removed an useless redundancy in Entries with the corresponding database object
  • Digicode: Remove implemented;
  • Digicode: buttonActionSettingsS
  • Fix: at start the Current date is wrong placed
  • Fix: when the last untabbed Entry disapears, checking overlapping did crash
  • shows the userID chooser from DigicodeViewController
  • swow the User Settings from DigicodeViewController
  • placed the Sync button on DigicodeViewController
  • removed the DigicodeView embed in the main view (just working now with the DigicodeViewController)

#0.36

  • fix about forcing the landscape display at launch,
  • moved the Digicode View to its own ViewController
  • the Digicode ViewController display clearly: "Add Entry" vs "Modify Entry"
  • prepared the "Remove Entry" feature (TODO: complete) (#todo = 83)

#0.35

  • included Replicator, for NoSQL synchronization,
  • checked replication with Apache CouchDB (https://couchdb.apache.org), in local OK, on device OK,
  • fix System Prefs, so can use address/credential/password from there,
  • migration: can work with database if not user defined;
  • the multi-users feature is disabled (needs too much updates / not essential now)
  • added the Entity Type to the docID; updated save; updated load using also the old docID;
  • can work with userID, as with no userID;

todo: migration: when an userID is set (via the Setting View), purpose convert/remove/ignore

#0.34

  • UI: can choose an User at start;
  • Entries not load at start, but when an User is set,
  • the last used User is purposed at start, (saved when chosen),
  • the userID setting is unactivated, to allow working with no user (needs update)
  • changed: the leftest Data not mandatory to be an Entry, can now be a Date (todo: improve this)
  • implemented a Setting View (todo: improve, load/save the settings)
  • implemented parameters as System Prefs (server address/password)(todo: missed userName)
  • force the display to landscape when at launch time

#0.33

  • added userID in Entry id; Save OK, Load OK
  • Load (from range) can remove old-style stored Entry (without userID)
  • Modify Entry changes the ID back to old-style: fixed
  • FIX: adding/modifying an Entry before the last didn't correctly update levels for the following Entries
  • FIX: adding/modifying an Entry before the last didn't correctly update the green/blue Dates
  • FIX: colors for Entry TextFields were not applied at launch
  • preparing Parameters Setting via System Prefs

#0.32

  • fix: adding Dates din't make them to appear if no Entry,
  • reconsidered the calculation for zoom parameters,
  • more compatibility for the future Swipe function

#0.31

  • refactored TextFields management,
  • fixed the #0.30 issue,
  • fixed an Entry position issue: not tabbed while too much at left to be visible

#0.30

  • added TextFields for orangeLevel and greenLevel (for time to reach)
  • added Lines drawing for these
  • fixed the currentDate flashing
  • fixing an issue: can crash if all Entries are tabbed; waiting refactoring to be efficient

#0.29

  • refactoring for tabNum (left/right)
  • added EasterEgg: "87:03", for debugging
  • added EasterEgg: "87:00", for debugging (remove all Entries)
  • made the line down from an Entry to take the color from this Entry level
  • added the CurrentDate TF to flash its ':' character

#0.28

  • fixing an issue: changed the EasterEgg Code and behavior ("87:01" adds Entries for the current Day, "87:02" for the previous)
  • ISSUE: editing an old Entry (more than 24h before) changes its date (its Day changes to the current Day) => really, editing a tabbed Entry caused to make it untabbed (while successors remain tabbed) -> FIXED
  • the CurrentDate makes the zoom to update if its field come across the view right border
  • FIX: index mismatch when tabbing an Entry

#0.27

  • FIX: some Date fields miss to be removed when in the Tab Zone (because no Entry field recovering was detected)

#0.26

  • HOT Fix: replaced all Time references, (from: 60*hh+mm) to a more precise description, because comparing two could fail with an unexpected behavior, if the difference was more than 24h.

#0.25

  • removed adding static Dates at launch, just add at Left and Right from the currentDate
  • fix: the y-position for the very first Entry field was wrong
  • displays a Black vertical line when Tabbed active, to delimit the "Tab Zone"
  • fixed the x-position for the first untabbed Entry, i.e. just after the the last tabbed one (recompute graphic limits and zoom)
  • doesn't draw graphic in the Tab Zone
  • did choose in the Tab mode, that the leftest Untabbed TextField will be a Date TextField => infinite loop when Tabbing a Date => Fixed (the following TextField is tabbed if it is an Entry)

#0.24

  • added a TextField for the Current Time (placed Vertically at middle View)
  • set the color of this textField to the Score color (corresponding to current Time)
  • added a Timer for this textField; the Timer updates its value, and its Color; actually based on a 20s repeating;

#0.23

  • made WMDisplayedEntries to deal with MWAbstractDateTextField (so, Dates and Entries) instead of just MWEntryTextField

  • gvDateTextFields: changed from [MWDateTextField] to WMDisplayedEntries (as gvDisplayedEntries was)

  • issue: when a Date was removed at Left, adding an Entry makes each time this Date to be added again, and removed again.

  • Fix: needed to remove more Dates in the Tabbed Mode (no Date in the Tab Zone)

  • Fix: all Tabbed Entries are now well placed.

#0.22,

  • activated the Tabbed mode, for Left;

#0.21,

  • refactored gvEntriesTextFields to a class (was an Array), with iterator protocol
  • fix in Level Calculation
  • can remove Dates textFold at left if found overlapping within DisplayEntries

#0.20,

  • refactoring: removed gvEntriesTextFields (using now the existing gvDisplayedEntries)

#0.19,

  • it's possible now to Edit Entries

#0.18,

  • improved Digicode reaction,
  • made possible to add Entries, for which Date is anterior to the last entered

#0.17,

  • conversion delay->reduction: Fixed, now can apply to other halfLife
  • halfLife ready to become a parameter,
  • conversion level_to_reach->delay

#0.16,

  • more dealing with full Dates instead of "hh:mm", which can cause errors placing or comparing elements

#0.15, ce1f1fa

  • added frame border for the digicodeView
  • add a class from a custom ScrollView
  • added a background gradient to the custom ScrollView
  • commit before Recommended Settings
  • ? Dates not displayed at start if no Entry

#0.14, 857772e

  • removed the timeView
  • added the scrollView
  • made the Digicode buttons bigger
  • improved the Digicode reaction
  • added an Easter Egg, to fill the current Day with known Entries
  • re-factorized the Level computation
  • added color changes according to the level (alert/red, warning/orange, green)
  • changed Level Computation to not automatically increase Level as done if new Entry
  • Fixed Unit Tests, with this

TODO: gradient on Levels

#0.13, cecd04c

  • compute level for each Entry, dealing with the remaining level from the previous Entry
  • added XCTests TODO: make that if the current time is before "06:00" (can be set?) the Dates range will be for the previous Day TODO: spray level addition when new Entry, e.g. (40) into (10*4) in 5 mn ?

#0.12 , d190507

  • draw the level from the last Entry to the last Date

#0.11, fc9c42d

  • fine usage of DAO for Entries
  • implemented WMDateUtils
  • lot of refactoring
  • tracking: displayed TextFields<->database relation for Entries
  • adding an Entry doesn't reload the whole data for the current Day

#0.10, bea3757

  • add vertical lines from Entries (blue color), shorten at bottom
  • did change lines color to grey for Date, and shorten at top
  • fix on Device rotation
  • refactored UITextField type entries and dates to MWDateTextField and MWEntryTextField
  • introducing data management as DAO,

#0.9, 5039a3f

  • added a Hints.md (to improve)
  • shorten vertical lines, managing with existin or not entries
  • fixes both on String->Ints and Ints->Strings
  • intercepts device rotation (with viewWillTransitionToSize)
  • FIX on new Entries positions

#0.8, cc89e48

  • rearanged all Entries, rearanged all Dates, applying a zoom function
  • FIX, mismatching Ints obtained from "HH:mm" (Entry) vs "HH" (Date)
  • adds a Date at left if a new Entry is minor than it, at right if a new Entry is major than it

#0.7, 46f5d29

  • made Entries textfield as not editable
  • made Absisses textfield as not editable
  • updated code to show Absisses at bottom
  • refactorized textFields building (both for Entries and Absisses)
  • FIX: 2-digits padding with new Entries
  • FIX comparing: Dates (as "HH" and Entries (as "HH:mm")
  • added elements to Dates each time an Entry is post to the last Date (needs a FIX)

#0.6 , 9daf189

  • CDTDatastore : added create, save, findData(forDay: String)
  • Digicode: FIX on filter

#0.5, 080f481

  • added CDTDatastore (CloudAnt) support via cocoapods (todo: CRUD)
  • added textFields for hours, with lines as absisses

#0.4

  • changed the view hierarchy because of alpha conflicts
  • improved the Time filter; moved it to the Digicode View

#0.3

  • changed Deployment Target to 11.4
  • fix for iOS prior to 13
  • filter Date Value when manually keyed (numbers can't be over 59)

#0.2

  • replaced the add Button by a gesture
  • fixed the UI placements

#0.1

  • made the essential UI,
  • can add a time and display it

#0.0.1

  • added function to set the value to the digicode to appear
  • added repartition within textFields, (needs FIX)
Présentation - Le Baigneur
    <link rel="icon" href="favicon.svg">
    <link rel="shortcut icon" href="favicon.png">
    <link rel="stylesheet" href="css/variables.css">
    <link rel="stylesheet" href="css/general.css">
    <link rel="stylesheet" href="css/chrome.css">
    <link rel="stylesheet" href="css/print.css" media="print">
    <!-- Fonts -->
    <link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
    <!-- Highlight.js Stylesheets -->
    <link rel="stylesheet" href="highlight.css">
    <link rel="stylesheet" href="tomorrow-night.css">
    <link rel="stylesheet" href="ayu-highlight.css">

    <!-- Custom theme stylesheets -->
</head>
<body>
    <!-- Provide site root to javascript -->
    <script type="text/javascript">
        var path_to_root = "";
        var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
    </script>

    <!-- Work around some values being stored in localStorage wrapped in quotes -->
    <script type="text/javascript">
        try {
            var theme = localStorage.getItem('mdbook-theme');
            var sidebar = localStorage.getItem('mdbook-sidebar');
            if (theme.startsWith('"') && theme.endsWith('"')) {
                localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
            }
            if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
            }
        } catch (e) { }
    </script>

    <!-- Set the theme before any content is loaded, prevents flash -->
    <script type="text/javascript">
        var theme;
        try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
        if (theme === null || theme === undefined) { theme = default_theme; }
        var html = document.querySelector('html');
        html.classList.remove('no-js')
        html.classList.remove('light')
        html.classList.add(theme);
        html.classList.add('js');
    </script>

    <!-- Hide / unhide sidebar before it is displayed -->
    <script type="text/javascript">
        var html = document.querySelector('html');
        var sidebar = 'hidden';
        if (document.body.clientWidth >= 1080) {
            try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
            sidebar = sidebar || 'visible';
        }
        html.classList.remove('sidebar-visible');
        html.classList.add("sidebar-" + sidebar);
    </script>

    <nav id="sidebar" class="sidebar" aria-label="Table of contents">

        <div class="sidebar-scrollbox">
        
        
            <!-- TITLE for TOC -->
            <ol class="chapter">
                    <li class="chapter-item affix"><li class="part-title">
                        <a href="http://pro.numericable.fr/chdelann/" style="text-decoration: none;"><strong>ChD</strong></a>
                        <p><i>Stories</i></p>
                    </li>
            </ol>
            <hr>
            <!-- OTHER PROJECT -->
            <!-- <ol class="chapter">
                <li class="chapter-item expanded ">
                    <li class="part-title">
                        <a href="../../STF/html/VersionLog.html">
                        STF</a></li></li>
            </ol> -->
            
            <ol class="chapter"><li class="chapter-item expanded "><a href="../STF/index.html"><strong aria-hidden="true">1.</strong> S.T.F.</a></li><li class="chapter-item expanded "><a href="1_presentation.html" class="active"><strong aria-hidden="true">2.</strong> Le Baigneur</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="1_presentation.html" class="active"><strong aria-hidden="true">2.1.</strong> Présentation</a></li><li class="chapter-item expanded "><a href="2workflow.html"><strong aria-hidden="true">2.2.</strong> Workflow</a></li><li class="chapter-item expanded "><a href="3fabrication.html"><strong aria-hidden="true">2.3.</strong> Fabrication</a></li><li class="chapter-item expanded "><a href="3fabrication1.html"><strong aria-hidden="true">2.4.</strong> Fabrication (suite)</a></li><li class="chapter-item expanded "><a href="4code.html"><strong aria-hidden="true">2.5.</strong> Code</a></li><li class="chapter-item expanded "><a href="5configuration.html"><strong aria-hidden="true">2.6.</strong> Configuration</a></li><li class="chapter-item expanded "><a href="6calibration.html"><strong aria-hidden="true">2.7.</strong> Calibration</a></li><li class="chapter-item expanded "><a href="7notesmpu6050.html"><strong aria-hidden="true">2.8.</strong> Notes sur MPU6050</a></li><li class="chapter-item expanded "><a href="8Roadmap.html"><strong aria-hidden="true">2.9.</strong> Roadmap</a></li></ol></li></ol>
            
            
            <!-- OTHER PROJECT -->
            <!-- <ol class="chapter">
                <li class="chapter-item expanded ">
                    <li class="part-title">myMoss</li>
                <a href="http://chdfree.free.fr/wanmore" target="_blank">Site Pro</a><br>
                <a href="https://gitlab.com/tontonCD" target="_blank">GitLab</a></li>

            </ol> -->
            
            <!-- OTHER LINKS -->
            <hr>
            <ol class="chapter">
                <li class="chapter-item expanded ">
                    <li class="part-title">Voir aussi...</li>
                <a href="http://chdfree.free.fr/wanmore" target="_blank">Site Pro</a><br>
                <a href="https://gitlab.com/tontonCD" target="_blank">GitLab</a></li>

            </ol>
            

        </div>
        <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
    </nav>

    <div id="page-wrapper" class="page-wrapper">

        <div class="page">
            <div id="menu-bar-hover-placeholder"></div>
            <div id="menu-bar" class="menu-bar sticky bordered">
                <div class="left-buttons">
                    <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                        <i class="fa fa-bars"></i>
                    </button>
                    <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                        <i class="fa fa-paint-brush"></i>
                    </button>
                    <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                        <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                        <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                        <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                        <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                        <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                    </ul>
                    <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                        <i class="fa fa-search"></i>
                    </button>
                </div>

                <h1 class="menu-title">Le Baigneur</h1>

                <div class="right-buttons">
                    <a href="print.html" title="Print this book" aria-label="Print this book">
                        <i id="print-button" class="fa fa-print"></i>
                    </a>
                </div>
            </div>

            <div id="search-wrapper" class="hidden">
                <form id="searchbar-outer" class="searchbar-outer">
                    <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                </form>
                <div id="searchresults-outer" class="searchresults-outer hidden">
                    <div id="searchresults-header" class="searchresults-header"></div>
                    <ul id="searchresults">
                    </ul>
                </div>
            </div>
            <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
            <script type="text/javascript">
                document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                    link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                });
            </script>

            <div id="content" class="content">
                <main>
                    <header>Présentation</header>

Page créée le : 01/10/2020 Mise à jour : 18/10/2020 Auteur : Christophe Delannoy

Présentation

Il existe pour les brasseurs amateurs, un instrument "DIY"1 assez légendaire (voire mythique), le iSpindle2, qui permet de mesurer la densité d'un brassin au cours de la fermentation primaire... et donc mieux la contrôler.

Le iSpindle est un tube contenant un micro contrôleur équipé d'un gyroscope, et pouvant communiquer en WiFi. Le principe est de le laisser flotter dans le brassin, et en fonction de la densité du liquide il va plus ou moins s'enfonce/s'incliner. Ces informations, fournies par le gyroscope, sont récupérées par Wifi, ce qui se fait sans ouvrir la cuve, ni prélèvement !

Le iSpindle est facile à fabriquer (quelques heures quand même) mais très complexe en à mettre en œuvre : quel serveur utiliser, quelle configuration pour ce serveur... J'ai passé vraiment beaucoup de temps sur une des solution proposée (FHEM, qui en fait n'est pas fait pour ça).

De surcroît il y a quelques bugs, par exemple c'est la valeur de l'accéléromètre qui est utilisée pour mesurer l'orientation, et non celle du gyroscope proprement dit3. Ça ne peut pas fonctionner !

Je propose donc ma solution.

Contraintes

Bien évidemment l'appareil ne sera pas alimenté par un transfo, mais par une batterie (type 18650).

Pourquoi ? lui même consomme faiblement, mais le Wifi beaucoup : au total quelque chose comme 170mA, ce qui peut paraître peu (moins de 0.6W en 3.3V)... seulement, une batterie de 1700m Ah ne pourra fournir que 170mA pendant 10h4, ce qui ne lui laisse que 10h d'autonomie !

a) La solution est que l'appareil se mette en mode "DeepSleep" ("sommeil profond")5, avec pour consigne de se réveiller après un certain temps (minium 1/4h) : il prend alors quelques secondes pour faire des mesures et les envoyer à un serveur, et se rendort à nouveau.

b) L'utilisation d'un Serveur est donc indispensable puisque il ne sera pas accessible durant les phases de sommeil.

Lequel ? Si on veut suivre la fermentation en l'affichant sur une courbe graphique (l'idéal...), celui-ci doit rester constamment allumé.

Comme je n'aime pas l'idée d'un PC constamment allumé il est décidé de créer un serveur sur une deuxième carte. Celle-ci pourra, elle, être connectée à une alimentation (ou à une batterie plus importante), et fonctionner en permanence.

c) Le serveur stocke les données de chaque connection Client, la consultation des données se fera par un navigateur web (éventuellement une application pour tablette) connectée à ce Serveur.

note

Initialement appelé "mySpindle", les apports au code on été tels (souvent "from scratch") que le projet a finalement été renommé en "myMoss"6. Je remercie toutefois, vivement, les auteurs du iSpindle pour leur incroyable idée.

liens

https://www.brassageamateur.com/wiki/index.php/Densim%C3%A8tre_Wifi_iSpindle

(TODO : iSpindle (github, ...), forums, ...)


Suite : Schéma de Fonctionnement


1

DIY : "Do It Yourself" = "à faire soi même", mais on peut en trouver déjà assemblés (plus cher...) 2: lien sur le iSpindle : // TODO

3

le module fait "gyroscope" plus "accéléromètre.

4

autonomie (calcul) : 1700mAh = 1700mA * 1h, soit 1700mA pendant 1h, de même que 1700mAh = 170mA * 10h, soit 170mA pendant 10h 5: En mode DeepSleep tout est arrêté sauf l'horloge interne (c'est elle qui le "réveille"), la consommation est alors de 0,020mA : 10000 fois moins !

6

"moss" en Anglais se traduit par "mousse" en Français, utilisé pour "bière" en argot (joke: "mousse" is a French slang word for "beer")

                <nav class="nav-wrapper" aria-label="Page navigation">
                    <!-- Mobile navigation buttons -->
                        <a rel="prev" href="../STF/index.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                            <i class="fa fa-angle-left"></i>
                        </a>
                        <a rel="next" href="1_presentation.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                            <i class="fa fa-angle-right"></i>
                        </a>
                    <div style="clear: both"></div>
                </nav>
            </div>
        </div>

        <nav class="nav-wide-wrapper" aria-label="Page navigation">
                <a rel="prev" href="../STF/index.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                    <i class="fa fa-angle-left"></i>
                </a>
                <a rel="next" href="1_presentation.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                    <i class="fa fa-angle-right"></i>
                </a>
        </nav>

    </div>

    <script type="text/javascript">
        window.playground_copyable = true;
    </script>
    <script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="searcher.js" type="text/javascript" charset="utf-8"></script>
    <script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="highlight.js" type="text/javascript" charset="utf-8"></script>
    <script src="book.js" type="text/javascript" charset="utf-8"></script>

    <!-- Custom JS scripts -->
</body>