1) Облако хранения данных, это ничто иное, как некий интерфейс, к которому можно обратиться с любого места программы чтоб получить какие-то данные.
Например: программа управления насосами отопления, кричит "Хочу знать Т на улице". Кто туда положил эти данные, эту программу не волнует. Это может быть датчик Т, а может быть и данные полученные основным сервером, через интернет. Данные в облаке есть, они актуальны, все остальное не важно.
В этом облаке, хранятся только данные, которые могут понадобиться кому угодно. Сюда попадают настройки системы, значения переменных состояния, да все что угодно. Но, при этом надо понимать, что данные должны быть уже обработанные и систематизированные.
Например: хранение Т на улице, это правильно. НО! при этом хранение моментальных данных с датчика Т, на улице, это уже не правильно. Прежде чем выкладывать данные в общее пользование, данные должны быть нормализованны. Тоесть, надо вначале сделать "усреднение" значение датчика, перевести значение датчика в градусы цельсия и только после этого сохранить в облако.
Конечно никто не может помешать, хранить там все что угодно, даже время в миллисекундах, только надо учитывать, сам процесс сохранения и извлечения данных из хранилища, является достаточно дорогим процессом. Для работы с облаком, у каждого модуля есть два метода SET и GET.
Рассмотрим, каждый блок "поближе".
Предположим, что мы можем написать ВСЁ! Давайте помечтаем...Для создания гибкой масштабируемой системы, поделим всю программу на блоки.
1) облако хранения public данных.
2) сама программа, это ничто иное, как куча маленьких модулей (тут и далее, термин "модуль" чаще имеет отношение к программному модулю, который в терминах ОС, является ничем иным как процессом), которые выполняются одновременно.
3) это порты ввода-вывода.
4) система обмена событиями.
2) Программа. Тут все достаточно просто, и все очень сложно. Просто с точки зрения логики, сложно с точки зрения реализации.
При написании Программы, надо учитывать несколько вещей, каждый модуль, должен быть как можно меньше, но при этом должен быть логически завершенным. Модуль должен писаться таким образом, чтоб он работал только с одним набором портов ввода-вывода. Если необходимо обработать сразу несколько портов, то модуль надо делить на несколько модулей, и связывать их событием.
Например: возьмем самый простой случай "включение света". Т.к. у нас блок ввода и блок вывода разные модули, то простая программа типа:
if IO1.Кнопка1.Состояние = ВКЛ then IO2.Вывод1.Состояние = ВКЛ
Превращается в более сложную конструкцию:
Первый модуль:
USE('IO1') // Прописываем, что модуль использует блок ввода-вывода №1
if IO1.Кнопка1.СтароеСостояние <> IO1.Кнопка1.Состояние then
DATACLOUD.SET("Свет. Гостиная.Группа1",100) // Значение в % от максимального освещения, для ON OFF это соответственно 0 - 100, для RGB это должно быть примерно так:
// DATACLOUD.SET("Свет.Гостиная.Группа1.RGB",'100,100,100')
IO1.Кнопка1.СтароеСостояние = IO1.Кнопка1.Состояние // Сохраняем новое состояние в переменной объекта
EVENT.PUSH("СВЕТ","Гостиная") // отправляем событие Свет, с параметром Гостиная
и второй модуль
USE('IO2') // Прописываем, что модуль использует блок ввода-вывода №2
// Подписка на событие Свет, модуль может быть как просто зацикленная программа, так и event активируемая программа, в данном случае, мы пишем именно событийный модуль
EVENT.SUBS("СВЕТ")
if EVENT.VALUE == "Гостиная" then
if DATACLOUD.GET("Свет. Гостиная.Группа1") == 100 then
IO2.Вывод1.Состояние = ON //ON это константа равная 1
else
IO2.Вывод1.Состояние = OFF //OFF это константа равная 0
3) Порты ввода-вывода, вообще-то тут надо хорошенько подумать, дело в том, что возможно ситуация, когда основной блок Умки с каким-то набором портов ввода-вывода, расширяется более глупым блоком, по протоколу i2c. Заставлять эту "глупую" Умку думать, конечно тоже придется, но надо решить, как сильно мы его можем нагружать. Возможно для таких Умок надо написать простейшую программу, которая будет подписана на события "Получить состояние" и "Установить состояние", событие соответственно может прислать только управляющий модуль. Сама программа может генерировать событие "Состояние изменилось" и посылается оно только управляющему модулю. В значении, отправляемом событием отправляется значение той переменной, которая изменилась, или должна быть изменена. Частный случай, когда все состояния изменяются или запрашиваются. Такая схема позволит на "глупой" Умке убрать блок работы с облаком данных, и использовать облегченную модель работы с событиями.
4) Система обмена событиями, это "нервная система" всей системы. Программные модули (просто программа) шлют друг другу сообщения, при этом один модуль может быть подписать на несколько сообщений, а может и только на одно, (или вообще не подписан). Чем больше у нас модулей именно "подписанных" тем больше их может работать, т.к. они всё основное время, буду просто спать, и ждать своего часа. В свою очередь, на одно сообщение, может быть подписано несколько модулей. Обьем пересылаемых данных, должен быть как можно меньше, чтоб не загружать сеть. Т.к. именно сообщений в сети будет больше всего. Но при этом и "мельчить" сильно тоже нельзя. Увеличивая количество сообщений, мы в свою очередь множим кол-во модулей, и обработчик событий будет расти.
Ну например.
Можно сделать событие "Свет", которое заставит все Умки управляющие светом проснуться, или сделать событие "Свет.Гостиная", тогда проснется только одна Умка, которая управляет светом в гостиной. При схеме из 5-ти Умок, это большой роли не влияет, но когда у нас в доме стоит скажем 10 щитов, и в каждом щите работает одина управляющая Умка, которая держит в своих руках еще десяток подчиненных "глупых" Умок, то лишний раз дергать всех выкрикивая на всю сеть "свет" уже не стоит. В общем, при проектировании, нужна будет разумная достаточность.
Теперь собственно программирование.
Самое сложное, в реализации, это "Облако данных". К реализации этой идеи можно подойди с разных сторон. Как варианты:
1) Делаем метод DATACLOUD.SET, он генерит событие EVENT.PUSH("DATACLOUD",value), на это событие подписаны все Умки, на уровне ОС. Когда событие пришло Умке, он сверяется с таблицей "нужности" (которая генерируется автоматом "прекомпилятором"), и если данные нужны, то сохраняется в локальное хранилище, а когда запустится метод DATACLOUD.GET, то лезем в свое собственное локальное хранилище и получаем нужные нам данные. При такой схеме "дорогой" является операция сохранения в облаке, т.к. заставляет всех Умок проснутся, и обработать событие, но при этом операция чтения, является быстрой и дешевой. Что очень хорошо, т.к. обычно чаще читаем, чем сохраняем.
Давай подумаем о других вариантах
2) ну самый фантастический вариант, это "выделенная база данных" когда отдельный модуль управляет облаком. Метод SET туда заливает данные, метод GET оттуда их берет. Реализовать проще всего, не надо делать никакой "предкомпиляции" и "анализа" проекта, все просто работает и все. Этот-же модуль можно заставить работать менеджером событий. Подписываясь на событие мы ставим Умку в очередь подписки, генерируя событие, мы отправляем данные для всех подписанных Умок. Тоже реализуется достаточно просто. Но при этом теряем в надежности. Хотя если предусмотреть процедуру дублирования, и передачи управления дублёру, можно получить не убиваемую систему. Даже разделив пополам сеть, в новой сети автоматом создастся еще один менеджер, который возьмет на себя всё управление. Ну... настолько на сколько это возможно будет. Сеть из одной Умки, тоже будет работать.
3) вариант "из пушки по воробьям". Для обработки событий и облака, берем комп. Обработчик пишем на языке высокого уровня, и радуемся, что у нас все работает. Такое решение позволит менять программу на лету, подписывать и отписывать модули на события буквально движением пальца. Можно будет организовать хранилище облака в какойнить базе данных, что позволит делать анализы данных и все что угодно буквально в LIVE режиме. Хорошо, и для первого варианта реализации, очень даже подходит.
Для написания программных модулей можно использовать родной компилятор, и писать их на C++. Предварительно прогнав программу через "прекомпилятор" можно получить набор отдельных программ для каждой Умки. Решение какой программный модуль, на какой Умке, будет выполняться решается по тому, какие порты ввода вывода, этот программный модуль использует. Если программному модулю порты и вовсе не нужны, то решение о том, какая умка его обрабатывает должно задаваться или в ручную, или по принципу "всем понемногу".
Вся программа должна работать на ОС реального времени, причем не обязательно вытесняющая, достаточно просто обработки просто цепочки процессов.