Le Windows Store for Business de Microsoft est enfin là !

Après plusieurs mois d’attente le « Business Store » est enfin disponible et accessible gratuitement avec quelques prérequis :

  • Avoir un Azure Active Directory.
  • Des postes clients sous Windows 10 uniquement (Desktop/Phone)
  • (Énormément de patience pour le déploiement…)

(Pour les clients sous Windows 8 et Windows 8.1, ou ceux qui n’ont pas d’Azure AD, nous avons une solution pour vous !)

Comment s’inscrire ?

La première étape se déroule sur https://businessstore.microsoft.com, l’administrateur général de l’AD se connecte avec le compte de l’organisation.

La création du store est immédiate, mais son déploiement prend du temps.

L’administrateur peut attribuer les droits à d’autres utilisateurs de l’AD de gérer le store (directement dans le BO du store) pour les actes d’achats, d’attributions de licences et de publications.

login.png

Les applications grand public :

Après « l’achat » (visiblement pour l’instant nous ne pouvons acheter que des applications gratuites), l’attribution de la licence peut être globale (au niveau de l’organisation), par groupe ou par utilisateur. Le déploiement prend plusieurs heures (+12h)

achat.png

 Les application LOB :

Le processus est long puisqu’il se passe en plusieurs actes :

  • Premier acte :
    • L’administrateur invite un éditeur LOB avec une adresse mail pour que celui-ci puisse attribuer à l’organisation une ou des applications. (Éditeur LOB = un simple compte de développement qui possède un accès au Windows Dev Center https://dev.windows.com)

lob.png

  • Deuxième acte :
    • L’éditeur publie ou met à jour une application en précisant dans la section « tarifs et disponibilités », le store d’entreprise qu’il souhaite viser (une même app LOB peut être diffusée sur différents Business Stores).
  • Troisième acte :
    • Après la validation de l’application par Microsoft (cette étape dure entre quelques heures à quelques jours), l’application est disponible coté BO du Business Store, et c’est à ce moment là que l’administrateur peut l’ajouter au catalogue, de la même manière qu’une application grand public (avec les droits qui vont avec et l’attente du déploiement qui prend aussi plusieurs heures)

Configuration du poste client (Desktop/Phone):

L’étape la plus simple se passe coté poste client où il suffit de se connecter ou d’ajouter (si ce n’est pas déjà le cas) le compte utilisateur rattaché à l’AD directement dans l’application du store. Un nouvel onglet va apparaitre avec la liste des applications attribuées que l’utilisateur pourra alors installer.

Sans titre.png

A vos déploiements !

Microsoft Ignite 2015 – SharePoint Online and OneDrive for Business Management and Control – Mercredi 6 mai

Microsoft Ignite 2015 – SharePoint Online and OneDrive for Business Management and Control – Mercredi 6 mai

SharePoint Online and OneDrive for Business Management and Control
Code : BRK3123

Par Adrien,
Pôle SharePoint MCNEXT

• Niveau : 300
• Cible : IT Influance & implementers
• Présentateur : Chris Bortik, Productivity Architect Microsoft

Lire la suite

EDF, Azure, Windows Phone et du Micro Framework

DISCLAIMER : avant toute chose, l’auteur n’est pas responsable pour toute action, accident, etc. survenue lors du montage, l’installation, l’utilisation, etc. des procédés décrits dans cet article !

L’objet de ce post est de présenter la solution que j’ai pu mettre en place pour récupérer la consommation électrique de la maison en temps réel, et la consulter sur mon Windows Phone.

 

Liste des courses

Pour ceci nous avons besoin :

  • D’un compteur ERDF numérique. Si vous disposez d’un ancien modèle (la version à disque rotatif), vous pouvez demander le changement avec des frais pas trop importants.
  • D’activer l’option « teleinfo » sur votre compteur. Par défaut il est installé.
  • D’un compte Azure pour stocker les informations.
  • D’une carte Micro Framework. Le code en exemple s’applique sur du Micro Framework 4.2.Ma recommandation actuelle est un bon compromis : la FEZ Cerbuino, disponible sur le site du producteur (https://www.ghielectronics.com/catalog/product/473 ).
  • A l’époque où j’ai fait tourner le code, j’ai utilisé un FEZ Domino mais qui n’est plus en vente.
  • D’un petit montage électronique, avec des composants disponibles sur ebay ou chez Farnell/Mouser/etc. Le prix des composants est ridicule :
    • Un optocoupleur SFH620 (j’ai utilisé une Vishay SFH6206-2)
    • 1 résistance 4.7KOhm
    • 1 résistance 1.2KOhm

 

Schéma physique

D’abord pour le montage, nous avons besoin de réaliser le schéma suivant :

schéma électronique

Dans la partie droite du schéma, le montage se branchera sur la carte Micro Framework. A gauche du schéma arrivent les fils reliés à la sortie Teleinfo du compteur électrique (I1 et I2) :

schéma montage

On note :

  • Le branchement en 5V de la carte et du petit montage électronique. Un chargeur USB peut faire l’affaire.
  • La liaison masse sur la carte Micro Framework et du petit montage (GND)
  • La double liaison avec le compteur (I1 et I2)
  • La liaison avec la COM1 IN sur la carte Micro Framework.

 

Le protocole Teleinfo

Peu connu, cette fonctionnalité permet de récupérer en mode port série le flux réel des informations EDF. Les caractéristiques du port exposé par le compteur : 1 200 bps, 7 bit, Parity Even, Stop Bit One.

Pour les trames envoyées, le protocole est plutôt bien documenté :

http://www.planete-domotique.com/notices/ERDF-NOI-CPT_O2E.pdf (documentation « officielle »)

http://bernard.lefrancois.free.fr/teleinfo.htm (exemples de trames)

Personnellement j’ai de l’heure creuse/heure pleine (HC/HP) à la maison, monophasé. Passer dans du triphasé ou autre revient à interpréter les bonnes trames.

 

Le code

Pour la partie code Micro Framework, rien de plus facile :

On commence déjà par se faire une classe qui encapsule les parties qui nous intéressent :

public class EdfReading
{
  public string NoCompteur { get; set; }
  public string PeriodeTarifaireEnCours { get; set; }
  public string PuissanceApparente { get; set; }
  public string IndexHeuresCreuses { get; set; }
  public string IndexHeuresPleines { get; set; }
}

Ensuite on démarre la lecture :

  • déclaration des variables importantes :
const byte startByte = 0x002;
const byte endByte = 0x003;
static Encoding enc = Encoding.UTF8;
static EdfReading currentReading;
  • déclaration du port sériel :
static SerialPort serialPortEdf = new SerialPort("COM1", 1200, Parity.Even, 7);

En plus il faut rajouter dans le Main :

serialPortEdf.StopBits = StopBits.One; // pas accessible dans le constructeur le stopbit… 
InitiateEdfPort();

Cet appel de fonction pointe vers :

private static void InitiateEdfPort()
{
  // ouverture du port
  if (serialPortEdf.IsOpen)
    serialPortEdf.Close();
 
  serialPortEdf.DataReceived += new SerialDataReceivedEventHandler(EdfPacketReceived);
  serialPortEdf.Open();
}

L’interprétation des packets se fait dans EdfPacketReceived, avec un petit bémol :

    static void EdfPacketReceived(object sender, SerialDataReceivedEventArgs e)
    {
        var incoming = new byte[serialPortEdf.BytesToRead];
        serialPortEdf.Read(incoming, 0, incoming.Length);

        if (incoming == null || incoming.Length < 5)
            return; // du bruit sur le reseau….

        if (currentPosition + incoming.Length > cursorByteArray.Length)
        {
            // ah, il y a un probleme... on est au bout du buffer sans pourtant avoir la trame de fin
            currentPosition = 0;
            cursorByteArray = new byte[buffersize]; // repartir de zero
        }

        // concatener un peu..
        System.Array.Copy(incoming, 0, cursorByteArray, currentPosition, incoming.Length)

        currentPosition += incoming.Length;
        // find startindex
        int startIndex = System.Array.IndexOf(cursorByteArray, startByte, 0);
        int endIndex = System.Array.IndexOf(cursorByteArray, startByte, startIndex + 1);

        // decommentez cette partie si vous voulez avoir la trame en DEBUG
        //string s = new String(Encoding.UTF8.GetChars(cursorByteArray));
        //Debug.Print(s);
        if (endIndex < 1 || startIndex < 0 || startIndex > endIndex)
        {
            return;// pas de trame valide encore
        }

        // si on est la ca veut dire
        // - trame edf valide (start, endbyte)
        // - on peut la lire</pre>
        // lire uniquement la partie qui nous interesse
        byte[] validPacket = new byte[endIndex - startIndex + 1];
        System.Array.Copy(cursorByteArray, startIndex, validPacket, 0, validPacket.Length);
        TranslateEdfProtocolIntoCurrentReading(validPacket);

        currentPosition = 0;
        cursorByteArray = null;
        cursorByteArray = new byte[buffersize];
    }

    static void TranslateEdfProtocolIntoCurrentReading(byte[] packets)
    {
        if (packets == null || packets.Length < 1)
            return;
        string adco = FindPacketValue(packets, "ADCO");
        string hchc = FindPacketValue(packets, "HCHC");
        string hphp = FindPacketValue(packets, "HCHP");
        string ptec = FindPacketValue(packets, "PTEC");
        string papp = FindPacketValue(packets, "PAPP

        if (hchc != null && hchc.Length > 1)
        {
            // la lecture est ici
            currentReading = new EdfReading()
            {
                IndexHeuresCreuses = hchc,
                IndexHeuresPleines = hphp,
                NoCompteur = adco,
                PeriodeTarifaireEnCours = ptec,
                PuissanceApparente = papp
            };
        }

      if (currentReading != null)
            Debug.Print("*** HP:" + currentReading.IndexHeuresPleines + " & HC:" + currentReading.IndexHeuresCreuses);
    }

    private static string FindPacketValue(byte[] packets, string packetName)
    {
        int position = FindIndexOf(packets, enc.GetBytes(packetName));
        if (position == -1) // not found...
            return string.Empty;

        int startByte = 0;
        int endByte = 0;
        for (int i = position; i < packets.Length; i++)
        {
            var b = packets[i];
            if (b == 0x20)
            {
                if (startByte == 0)
                    startByte = i;
                else if (endByte == 0)
                {
                    endByte = i; // end of packet reached..
                    break;
                }
            }
        }

       // find the value...
        byte[] valByte = new byte[endByte - startByte + 1];
        System.Array.Copy(packets, startByte, valByte, 0, endByte - startByte);
        return new String(System.Text.Encoding.UTF8.GetChars(valByte));
    }

    private static int FindIndexOf(byte[] arrayToSearchThrough, byte[] patternToFind)
    {
        if (patternToFind.Length > arrayToSearchThrough.Length)
            return -1;
        for (int i = 0; i < arrayToSearchThrough.Length - patternToFind.Length; i++)
        {
            bool found = true;
            for (int j = 0; j < patternToFind.Length; j++)
            {
                if (arrayToSearchThrough[i + j] != patternToFind[j])
                {
                    found = false;
                    break;
                }
            }
            if (found)
            {
                return i;
            }
        }
        return -1;
    }

On voit bien que j’ai dû créer une méthode pour trouver des arrays de bytes dans des arrays de bytes. Il ne faut pas oublier qu’on est sur un Micro Framework et qu’on n’a pas le Rolls habituel !

Du coup, si tout est bon, vous avez les valeurs dans currentReading, et vous pouvez ensuite envoyer les infos vers Azure, les afficher, etc.

Chez moi la carte Micro Framework qui fait la lecture du compteur n’est pas le même que cela qui communique avec Azure. Les deux sont reliées par un réseau RS485.

 

Partie Azure

Dans Azure j’ai créé un simple site MVC qui m’expose, en GET tout simple, une manière des stocker les infos dans une base SQL Azure.

La sécurité se fait par l’envoi d’une clé non-répétitive (Hint: prenez l’heure, prenez une key et composez votre token non-répétitif).

La partie qui va envoyer l’info dans Azure tourne sur un FEZ Panda 2 + un FEZ Connect. Mais si vous avez le Cerbuino Net, vous pouvez récupérer et envoyer les informations directement depuis la même carte. L’URL contiendra les valeurs (ex : http://monsiteweb/Sauvegarde?valeurHC=123&valeurHP=321&tokenSecret=ABCD )

    private static void CallWSWithUrl(string url)
    {
        for (int i = 0; i < 30; i++)
        {
            if (requestInProgress)
                Thread.Sleep(100);
            else
                break;
        }
        requestInProgress = true;

        using (HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url))
        {
            request.ContentType = "application/text";
            request.Method = "GET";
            request.Timeout = 4000;
            request.KeepAlive = false;

            try
            {
                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {
                    response.GetResponseStream().ReadByte();
                    Thread.Sleep(300);
                    response.Close();
                }
            }
            catch (Exception ex)
            {
                Debug.Print("WS ERROR: " + ex.Message);
            }
        }

        requestInProgress = false;
    }

Le résultat ?

tableau de valeurs dans Azure

On voit bien la sauvegarde des valeurs toutes les minutes, et la précision qui va nous permettre de calculer la consommation en Watt.

Un point d’attention : vu la volumétrie qui s’accumule, il faudra bien penser à indexer et optimiser la lecture de la table. Un exemple pour récupérer la consommation par heure, en HC/HP, d’une manière optimale, pour une période donné :

SELECT
  MAX(ReadingValueHP) as hp,
  MAX(ReadingValueHC) as hc,
  CONVERT(DateTime, Convert(NVARCHAR, CONVERT(Date, ReadingDate))+' '+CONVERT(NVARCHAR, DATEPART(hour, ReadingDate)) + ':00') as Readingdate
FROM EdfReading
WHERE ReadingDate >= @start
AND ReadingDate <= @end
GROUP BY CONVERT(DateTime, CONVERT(NVARCHAR, CONVERT(Date, ReadingDate))+' '+CONVERT(NVARCHAR, DATEPART(hour, ReadingDate)) + ':00')

Et la même chose pour avoir la valeur par jour (on fera la différence par la suite, sur le phone) :

SELECT MAX(ReadingValueHP), MAX(ReadingValueHC), CONVERT(Date, Readingdate) as ReadingDate
FROM EdfReading
WHERE ReadingDate >= @start
AND ReadingDate <= @end
GROUP BY CONVERT(Date, Readingdate)

 

Partie Windows Phone

screenshot windows phone 2 screenshot windows phone 1

Pour la partie Phone, l’application récupère simplement les valeurs du site, et on fait la différence entre les valeurs pour avoir la consommation réelle.

Des totaux sont proposés pour la période affichée.

Les deux parties à retenir :

  • le calcul des Watts :
private static void CalculateConsumption(EdfReading[] results, out double totalKWHP, out double totalKWHC, out double indexHP, out double indexHC, out List<EdfReadingExtended> items)
{
var minValHP = results.Min(x => x.ReadingValueHP);
var minValHC = results.Min(x => x.ReadingValueHC);

indexHP = results.Max(x => x.ReadingValueHP);
indexHC = results.Max(x => x.ReadingValueHC);

totalKWHP = indexHP - minValHP;
totalKWHC = indexHC - minValHC;

items = new List<EdfReadingExtended>();
var orderedRdgs = results.OrderBy(x => x.ReadingDate).ToArray();

var cursorHP = minValHP;
var cursorHC = minValHC;
var cursorDate = results.Min(x => x.ReadingDate);

foreach (EdfReading rdg in orderedRdgs)
{
// start digging...
// find out the consumption in watts
double hours = (rdg.ReadingDate - cursorDate).TotalHours;

// now, we should get the wattage for the given interval
var hcConsumption = (rdg.ReadingValueHC - cursorHC);
var hpConsumption = (rdg.ReadingValueHP - cursorHP);

items.Add(new EdfReadingExtended()
{
ReadingDate = rdg.ReadingDate,
ReadingValueHC = hcConsumption / (double)1000,
ReadingValueHP = hpConsumption / (double)1000,
KW = (int)(hcConsumption / hours + hpConsumption / hours)
});

cursorHC = rdg.ReadingValueHC;
cursorHP = rdg.ReadingValueHP;
cursorDate = rdg.ReadingDate;
}
}
  • et l’utilisation des graphs DataVisualisation Toolkit. J’ai modifié légèrement les sources pour que je puisse :
    • slider gauche/droite pour décaler l’axe de temps
    • pinch pour changer l’échelle de temps (minute/heure/semaine/mois/période)

Depuis ma galère initiale pour le porter sur WP 8.0, il existe en package NuGet désormais, mais sans les deux features.

 

Conclusion et lecture supplémentaire

J’espère avoir suscité votre curiosité sur le sujet.

L’application tourne chez moi depuis plus d’un an, sans soucis majeur. La carte Micro Framework est dehors dans un boitier étanche, et elle résiste sans soucis à des températures extérieures entre -15 degrés l’hiver et +35 l’été. Donc une belle surprise pour une carte qui n’est pas prévu pour le milieu industriel.

Le code est parfois rudimentaire, et je m’excuse par avance si vous trouvez des raccourcis de geek.

La semaine prochaine, je vais essayer de vous expliquer le même processus, mais avec mon compteur d’eau (qui n’est pas avec des impulsions !).

En attendant, si vous avez des commentaires, n’hésitez pas à m’en faire part. Le code source ne sera ni publié, ni diffusé intégralement. Je pense avoir donné toutes les informations pour vous faire bien démarrer en revanche.

Mes points de départ :

http://blog.cquad.eu/2012/02/02/recuperer-la-teleinformation-avec-un-arduino/

http://www.planete-domotique.com/blog/2010/03/30/la-teleinformation-edf/

 

Alex.

Débuguer une Universal Windows app et d’une application Cordova dans Visual Studio

Petit rappel : Vu l’architecture du projet (Applications natives en Universal App + application cordova) il faut bien penser à ajouter les fichiers copiés depuis le shared project en as link dans l’application cordova. C’est le seule moyen de débuguer/modifier le bon fichier.

 

Dans les applications universelles aucune configuration spéciale n’est nécessaire, Visual Studio gère parfaitement le debug. Il suffit de lancer l’application en mode debug et avoir accès dès le lancement au dom ainsi qu’aux points d’arrêts. Les choses se compliquent légèrement avec les applications cordova. En effet Visual studio met plusieurs secondes (voir minutes) avant d’attacher correctement et d’une façon stable le debugger. Et si on souhaite débuguer les premières lignes qui s’exécutent lors du lancement de l’application, cela devient rapidement compliqué, voir impossible.

Deux solutions existent :

  • La première (mais qui ne marche que si l’application s’initialise correctement = pas de crash au démarrage) c’est simplement via la console JavaScript de Visual Studio d’appeler la méthode window.location.reload() la page index.html est rechargée = les scripts se ré exécutent et on a donc accès aux debug des premières lignes de code.
  • La deuxième c’est de créer un mode debug avec une étape intermédiaire qui consistera à avoir un fichier index.html qui charge le stricte minimum de fichiers qui contient un lien (button) qui va nous permettre de naviguer vers une deuxième page qui va charger le reste des fichiers. Avec cette formule on s’assure du démarrage de l’application, on peut attendre que le debugger Visual Studio soit correctement attaché pour pourvoir charger les autres fichiers.

 

Le débogage/déploiement sous iOS requière un mac et l’installation des outils de build:

  • (Mac) Depuis le terminal lancer la commande désinstallation: sudo npm install -g vs-mda-remote –user=$USER ($user = l’utilisateur courant)
  • (Mac) Après l’installation lancer la commande: vs-mda-remote –secure false
  • Configurer Visual Sutdio: Tools => Options => Tools for Apache Cordova => remote Agent configuration:
    • Enable remote iOS processing = True
    • Host : adresse ip du mac de build.

Le déploiement peut se faire avec le simulateur ou un device.

Avec ces quelques notes vous avez maintenant les outils pour pourvoir débugger facilement votre nouvelle application.

Universal Windows app et Cordova avec WinJS

L’architecture que je conseil pour cibler les trois (quatres) plateformes, c’est de partir principalement d’un projet natif Universal app (Windows 8.1/ Windows Phone) en HTML5 et de créer un projet Cordova à l’aide du plugin Visual studio.

Ensuite pour brancher l’application Cordova avec le projet shared, il faut écrire un script (robocopy) à exécuter avant le build pour copier les fichiers du projet shared vers le projet cordova:

(robocopy ..\UniversalApp.Shared\ . /E /XF UniversalApp.Shared.*)^& IF %ERRORLEVEL% LEQ 1 exit 0

Et modifier le fichier de projet (jsproj) pour lancer cette exécution:

<Target Name= »BeforeBuild »>
<Message Text= »### BeforeBuild ### » Importance= »high » />
<Exec Command= »prebuild.bat » />
</Target>

Mais pour pouvoir débugguer les fichiers copiers, il faut aussi créer la structure des dossiers et ajouter les fichiers en as link.

Pour ajouter WinJS à vos projets vous pouvez passer par nuget (qui ne marche pas avec les projets shared pour le moment) ou récupérer directement la dernière version stable disponible depuis le repo github. Vous pourrez ensuite ajouter les fichiers WinJS.js, css ui-light.css ou ui-dark .css ainsi que la typo Symbols.ttf dans le dossier scripts du projet shared (cette version de WinJS sera aussi utilisée avec les Universel Apps)

Enfin il reste à inclure les références dans les fichiers default.html et index.html. Votre projet est ainsi prêt et on peut lancer le développement de notre application cross-plateforme.

Note importante: l’initialisation de l’application est différente en WinRT et en Cordova. Sous Windows on va conserver le fichier default.js, et pour le projet Cordova, on va modifier le fichier équivalent, index.js, pour initialiser correctement notre application.

Un exemple de solution est disponible ici

WinJS dans une application cross plateforme Cordova

Depuis avril 2014, WinJS le Framework SPA de Microsoft est devenu libre (disponible sur github) et  surtout cross-platform.
C’est avec ces nouvelles possibilités qu’on peut maintenant l’utiliser sur d’autres plateformes que Windows 8/Phone 8.1.

Dans cette série de posts, je vais donc aborder le développement multiplateforme d’application avec WinJS.

Build 2014 – Migration d’une application Windows Phone et Windows 8 vers les Universal Apps (Channel 9) : Stéphanie Hertrich, expert technique Microsoft France, reçoit John Thiriet, MVP client dev chez MCNEXT – via @ch9