EspHome custom component - c++

i have a probleme with custom code in esphome..
There is the error :
src/screen.h:23:59: error: cannot convert 'MyCustomComponent::MyCustomComponent(esphome::template_::TemplateNumber*&, esphome::template_::TemplateNumber*&, esphome::template_::TemplateNumber*&, esphome::homeassistant::HomeassistantTextSensor*&)::<lambda(String)>' to 'std::function<void(std::__cxx11::basic_string<char>)>'
23 | { str = str_n; });
| ^
and the code :
MyCustomComponent(esphome::template_::TemplateNumber *&_led_r,esphome::template_::TemplateNumber *&_led_g,esphome::template_::TemplateNumber *&_led_b,esphome::homeassistant::HomeassistantTextSensor *&_str)
{
_led_r->add_on_state_callback([this](float led_r_n)
{ led_r = led_r_n; });
_led_g->add_on_state_callback([this](float led_g_n)
{ led_g = led_g_n; });
_led_b->add_on_state_callback([this](float led_b_n)
{ led_b = led_b_n; });
_str->add_on_state_callback([this](String str_n)
{ str = str_n; });
}
I'm really lost..
thank you in advance
EDIT :
here is my code :
here is my code, in case I specify that I run this on a HomeAssistant instance with EspHome in version 2022.8.3
#include "esphome.h"
#include <Wire.h>
#include "rgb_lcd.h"
class MyCustomComponent : public Component, public CustomAPIDevice {
public:
rgb_lcd lcd;
bool enable = false;
int led_r = 0;
int led_g = 0;
int led_b = 0;
String str = "ff";
MyCustomComponent(esphome::template_::TemplateNumber *&_led_r,esphome::template_::TemplateNumber *&_led_g,esphome::template_::TemplateNumber *&_led_b,esphome::homeassistant::HomeassistantTextSensor *&_str)
{
_led_r->add_on_state_callback([this](float led_r_n)
{ led_r = led_r_n; });
_led_g->add_on_state_callback([this](float led_g_n)
{ led_g = led_g_n; });
_led_b->add_on_state_callback([this](float led_b_n)
{ led_b = led_b_n; });
_str->add_on_state_callback([this](String str_n)
{ str = str_n; });
}
void setup() override {
lcd.begin(16, 2);
}
void loop() override
{
lcd.setRGB(led_r,led_g,led_b);
}

As shown here
void esphome::text_sensor::TextSensor::add_on_state_callback(std::function< void(std::string)>callback)
You should use std::string instead of String (Arduino string), those are incompatible.
I'm not sure what you're going to do with String str = "ff"; but In case you still want to use Arduino String, you should be able to use like
_str->add_on_state_callback([this](std::string str_n)
{ str = String(str_n); });

Related

QUnit testing a function which leans on document properties

I'm trying to write some unit tests for an Apps Script add-on designed for Google Docs. A few of the functions I'd like to have unit tests for call PropertiesService.getDocumentProperties(). A simple example function in my add-on:
function baseFontSize() {
var baseFontSize = JSON.parse(
PropertiesService.getDocumentProperties().getProperty('baseFontSize'));
if (baseFontSize === null) {
baseFontSize = JSON.parse(
PropertiesService.getUserProperties().getProperty('baseFontSize'));
if (baseFontSize === null) {
PropertiesService.getUserProperties().setProperty('baseFontSize', '11');
baseFontSize = 11;
}
PropertiesService.getDocumentProperties()
.setProperty('baseFontSize', JSON.stringify(baseFontSize));
}
return baseFontSize;
}
I'm writing my tests with the QUnit for Google Apps Script library:
function doGet(e) {
QUnit.urlParams(e.parameter);
QUnit.config({title: 'My test suite'});
QUnit.load(testSuite);
return QUnit.getHtml();
}
QUnit.helpers(this);
function testSuite() {
// some module() and test() calls deleted for brevity...
test('baseFontSize', function() {
// PropertiesService.getDocumentProperties() === null
// how to test baseFontSize()?
});
// more module() and test() calls...
}
Since the test suite is not running within a document, there are no document properties. It seems that the only way to test my function would be to mock the getDocumentProperties function. Of course, the only Apps Script mock/stub libraries I can find are either meant to test within a Node.js environment, or are not sufficiently complete for my needs, which means I would have to roll my own.
While I still hope to find a more elegant solution, until that occurs I have thrown together a simple stub framework based on the SinonJS API, and I'm injecting the stub into my function to be tested (since I can't actually stub PropertiesService, as it's frozen).
Roughly, my solution (my project already includes Underscore, so I take advantage of it where I can):
function stub(object, property, impl) {
const original = object[property];
if (_.isFunction(impl)) object[property] = wrapFunction(impl);
else object[property] = wrapFunction(function() { return impl; });
object[property].restore = function() {
if (!_.isUndefined(original)) object[property] = original;
else delete object[property];
};
return object[property];
}
function wrapFunction(fn) {
const properties = _.mapObject({
get callCount() { return calls.length; },
get called() { return calls.length > 0; },
get notCalled() { return calls.length === 0; },
// etc...
}, function(v, k, o) { return Object.getOwnPropertyDescriptor(o, k); });
const calls = [];
const wrappedFn = function() {
const args = Array.prototype.slice.call(arguments);
var error;
var returnVal;
try { returnVal = fn.apply(this, args); }
catch (e) { error = e; }
calls.push({
thisObj: this,
params: args,
error: error,
returnVal: returnVal,
});
return returnVal;
};
Object.defineProperties(wrappedFn, properties);
return wrappedFn;
}
Then, my test:
test('baseFontSize', function() {
const propService = {};
stub(propService, 'getDocumentProperties', fakeGetProperties());
stub(propService, 'getUserProperties', fakeGetProperties());
equal(baseFontSize(propService), 11);
});
//...
function fakeGetProperties() {
const map = {};
const container = {
deleteAllProperties: function() {_.each(map, function(v, k){depete map[k];});},
deleteProperty: function(k) { delete map[k]; },
getKeys: function() { return Object.keys(map); },
getProperties: function() { return _.clone(map); },
getProperty: function(key) { return map[key] || null; },
setProperties: function(obj, deleteOthers) {
if (deleteOthers) container.deleteAllProerties();
_.each(obj, function(v, k) { map[k] = v; });
},
setProperty: function(key, value) { map[key] = value; },
};
return function() { return container; };
}
And the edited version of my function to test, with DI for PropertiesService:
function baseFontSize(propService) {
if (_.isUndefined(propService)) {
propService = PropertiesService;
}
var baseFontSize = JSON.parse(
propService.getDocumentProperties().getProperty('baseFontSize'));
if (baseFontSize === null) {
baseFontSize = JSON.parse(
propService.getUserProperties().getProperty('baseFontSize'));
if (baseFontSize === null) {
propService.getUserProperties().setProperty('baseFontSize', '11');
baseFontSize = 11;
}
propService.getDocumentProperties()
.setProperty('baseFontSize', JSON.stringify(baseFontSize));
}
return baseFontSize;
}

attributes are not defined with babel 6

I have an Ember app with ember-computed-decorators and I have this kind of model :
import DS from 'ember-data';
import {alias} from 'ember-computed-decorators';
export default DS.Model.extend({
#alias('customData.email') email
});
It worked with ember-cli-babel version 5 but I updated to the version 6 with tranform-decorator-legacy and I have this error :
email is not defined
I reproduced it with a simple js script like this :
function dec(target, name, descriptor) {
const method = descriptor.value;
descriptor.value = function(...args) {
return 'hello';
}
}
const Foo = {
#dec test
}
console.log(Foo.test);
And I have the same error.
This works :
function dec(target, name, descriptor) {
const method = descriptor.value;
descriptor.value = function(...args) {
return 'hello';
}
}
const Foo = {
#dec
test() {
return 'test';
}
}
console.log(Foo.test());
I think #dec test is strange but it worked with babel 5. What's the solution ?
Edit
Here is what's generated by ember :
define('tiny/models/subscription', ['exports', 'ember-data', 'ember-computed-decorators'], function (exports, _emberData, _emberComputedDecorators) {
function _createDecoratedObject(descriptors) { var target = {}; for (var i = 0; i < descriptors.length; i++) { var descriptor = descriptors[i]; var decorators = descriptor.decorators; var key = descriptor.key; delete descriptor.key; delete descriptor.decorators; descriptor.enumerable = true; descriptor.configurable = true; if ('value' in descriptor || descriptor.initializer) descriptor.writable = true; if (decorators) { for (var f = 0; f < decorators.length; f++) { var decorator = decorators[f]; if (typeof decorator === 'function') { descriptor = decorator(target, key, descriptor) || descriptor; } else { throw new TypeError('The decorator for method ' + descriptor.key + ' is of the invalid type ' + typeof decorator); } } } if (descriptor.initializer) { descriptor.value = descriptor.initializer.call(target); } Object.defineProperty(target, key, descriptor); } return target; }
exports['default'] = _emberData['default'].Model.extend(_createDecoratedObject([{
key: 'mail',
initializer: function initializer() {
return _emberData['default'].attr();
}
}, {
key: 'email',
decorators: [(0, _emberComputedDecorators.alias)('mail')],
initializer: function initializer() {
return email;
}
}]));
});
Here is what's generated by ember-cli-babel version 6 :
define('tiny/models/subscription', ['exports', 'ember-data', 'ember-computed-decorators'], function (exports, _emberData, _emberComputedDecorators) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
var desc = {};
Object['ke' + 'ys'](descriptor).forEach(function (key) {
desc[key] = descriptor[key];
});
desc.enumerable = !!desc.enumerable;
desc.configurable = !!desc.configurable;
if ('value' in desc || desc.initializer) {
desc.writable = true;
}
desc = decorators.slice().reverse().reduce(function (desc, decorator) {
return decorator(target, property, desc) || desc;
}, desc);
if (context && desc.initializer !== void 0) {
desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
desc.initializer = undefined;
}
if (desc.initializer === void 0) {
Object['define' + 'Property'](target, property, desc);
desc = null;
}
return desc;
}
var _dec, _desc, _value, _obj, _init;
exports.default = _emberData.default.Model.extend((_dec = (0, _emberComputedDecorators.alias)('mail'), (_obj = { email: email
}, (_applyDecoratedDescriptor(_obj, 'email', [_dec], (_init = Object.getOwnPropertyDescriptor(_obj, 'email'), _init = _init ? _init.value : undefined, {
enumerable: true,
configurable: true,
writable: true,
initializer: function initializer() {
return _init;
}
}), _obj)), _obj)));
});
I have the same result with babel 5.

Reading objects from webservice actionscript

I need to read objects and save them in array. I did that on c# but can't figure out how to do that on actionscript.
c# example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TestingWSDLLOad.ServiceReference2;
namespace TestingWSDLLOad
{
class Program
{
static void Main(string[] args)
{
ServiceReference2.Service1Client testas = new ServiceReference2.Service1Client();
SortedList<int, PlayListItem> playList = new SortedList<int, PlayListItem>();
int cc = 0;
foreach (var resultas in testas.GetPlayList(394570))
{
PlayListItem ss = new PlayListItem(resultas.Id, resultas.VideoId, resultas.Path);
playList.Add(cc, ss);
cc++;
}
Console.WriteLine(playList[0].Id);
Console.ReadKey();
}
}
public class PlayListItem
{
public int VideoId { get; private set; }
public string Path { get; private set; }
public int Id { get; private set; }
public PlayListItem(int id, int videoId, string path)
{
Id = id;
VideoId = videoId;
Path = path;
}
}
}
I know how to get a simple result from wsdl using actionscript, but don't know how to get objects with parameteres and save them.
Service has a method GetPlaylist(int value) which returns an array of objects (id, videoId, path). How to handle this and save them ?
Here is my as3:
package {
public class data extends CasparTemplate {
var flvControl:FLVPlayback;
var refreshTimer:Timer;
var videoList:Array;
var videoNew:Array;
var videoMaxIds:Array;
var videoNewMaxIds:Array;
var videoIndex:uint;
var videoIdFrom:uint;
var loopAtEnd:Boolean;
var _playListItems:Array;
var _playList:PlayListItem;
var gotNewPlaylist:Boolean;
var webService:WebService;
var serviceOperation:AbstractOperation;
public function data()
{
_playListItems = new Array();
flvControl = new FLVPlayback();
videoNew = new Array();
videoNewMaxIds = new Array();
videoIndex = 0;
videoIdFrom = videoMaxIds[videoIndex];
loopAtEnd = true;
gotNewPlaylist = false;
refreshTimer = new Timer(20000);
refreshTimer.addEventListener(TimerEvent.TIMER, getNewPlaylist);
refreshTimer.start();
flvControl.addEventListener(VideoEvent.COMPLETE, completeHandler);
flvControl.addEventListener(VideoEvent.STATE_CHANGE, vidState);
flvControl.setSize(720, 576);
flvControl.visible = true;
//addChild(flvControl);
var url:String = "http://xxx/yyy.svc?wsdl";
webService = new WebService();
webService.loadWSDL(url);
webService.addEventListener(LoadEvent.LOAD, BuildServiceRequest);
}
function BuildServiceRequest(evt:LoadEvent):void
{
webService.removeEventListener(LoadEvent.LOAD, BuildServiceRequest);
//serviceOperation.addEventListener(ResultEvent.RESULT, displayResult);
for (var resultas in webService.getOperation("GetPlaylist(394575)"))
{
trace(resultas.Id);
}
//serviceOperation = webService.getOperation("GetPlaylist");
//serviceOperation.arguments[{videoId: "394575"}];
}
private function displayResult(e:ResultEvent):void
{
trace("sss");
}
// Handle the video completion (load the next video)
function completeHandler(event:VideoEvent):void
{
if (gotNewPlaylist)
{
videoList = videoNew;
videoMaxIds = videoNewMaxIds;
videoNew = null;
videoNewMaxIds = null;
gotNewPlaylist = false;
videoIndex = 0;
} else
videoIndex++;
nextVideo();
}
private function vidState(e:VideoEvent):void {
var flvPlayer:FLVPlayback = e.currentTarget as FLVPlayback;
if (flvPlayer.state==VideoState.CONNECTION_ERROR) {
trace("FLVPlayer Connection Error! -> path : "+flvPlayer.source);
videoIndex++;
nextVideo();
} else if (flvPlayer.state==VideoState.DISCONNECTED) {
videoIndex++;
nextVideo();
}
}
function nextVideo():void
{
trace("Video List:"+videoList.toString());
if( videoIndex == videoList.length ){
if( loopAtEnd )
{
videoIndex = 0;
} else { return; }
}
flvControl.source = videoList[videoIndex];
if (videoIdFrom < videoMaxIds[videoIndex])
videoIdFrom = videoMaxIds[videoIndex];
trace(videoIdFrom);
}
}
}
internal class PlayListItem
{
private var _videoId:int;
private var _path:String;
private var _id:int;
public function get VideoId():int { return _videoId; }
public function get Path():String { return _path; }
public function get Id():int { return _id; }
public function set VideoId(setValue:int):void { _videoId = setValue };
public function set Path(setValue:String):void { _path = setValue };
public function set Id(setValue:int):void { _id = setValue };
public function PlayListItem(id:int, videoId:int, path:String)
{
_videoId = videoId;
_id = id;
_path = path;
}// end function
}
I think you were on the right track with your commented-out code. Be aware that the getOperation() will return an AbstractOperation, which in my mind is simply a pointer to the remote function. You can set arguments on the object, or simply pass the arguments when you call send(). I know some people have had issues with the argument property approach, so simply passing your arguments in the send function may be the smart way to go.
The following replace BuildServiceRequest and displayResult
private function BuildServiceRequest(evt:LoadEvent):void {
webService.removeEventListener(LoadEvent.LOAD, BuildServiceRequest);
serviceOperation.addEventListener(ResultEvent.RESULT, displayResult);
serviceOperation = webService.getOperation("GetPlaylist");
serviceOperation.send(394575);
}
private function displayResult(e:ResultEvent):void {
// Store the token as our array.
_playListItems = e.token;
var msg:String;
// Loop through the array
for each (var entry:Object in _playListItems) {
msg = "";
// For every key:value pair, compose a message to trace
for (var key:String in entry) {
msg += key + ":" + entry[key] + " ";
}
trace(msg);
}
}

Protobuf-net - list of objects with parent reference

I have a simple class with reference to parent object. All objects are in one list (even parent objects). Is it possible to keep references references after deserialization?
In my code I have something like this:
[ProtoContract]
public class ProtoItem
{
[ProtoMember(1)]
public int Value { get; set; }
[ProtoMember(2, AsReference = true)]
public ProtoItem BaseItem { get; set; }
}
And main looks like that:
static void Main()
{
var itemParent = new ProtoItem { Value = 1 };
var item2 = new ProtoItem { Value = 2, BaseItem = itemParent };
var item3 = new ProtoItem { Value = 3, BaseItem = itemParent };
var parentListToWrite = new List<ProtoItem> {itemParent, item2, item3};
const string file = "protofile.txt";
try { File.Delete(file); }
catch { };
using (var fs = File.OpenWrite(file)) { Serializer.Serialize(fs,
parentListToWrite); }
List<ProtoItem> readList;
using (var fs = File.OpenRead(file)) { readList =
Serializer.Deserialize<List<ProtoItem>>(fs); }
if (readList[0] == readList[2].BaseItem)
{
//how to make it equal?
}
if (readList[0] == readList[1].BaseItem)
{
//how to make it equal?
}
}
Is it possible to deserialize that if conditions works?
The protobuf specification doesn't have the notion of object identity. protobuf-net does (as an optionally enabled feature), but it doesn't currently work for list items directly, although I suspect it probably should. Since it would break the format, though, it would need explicit enabling if I fixed this.
But the following code works today - note that what I have done here is to wrap the top-level list items in a wrapper that just encapsulates the ProtoItem, but in doing so enables reference-tracking. Not ideal, but: it works.
using ProtoBuf;
using System.Collections.Generic;
using System.IO;
[ProtoContract(AsReferenceDefault=true)]
public class ProtoItem
{
[ProtoMember(1)]
public int Value { get; set; }
[ProtoMember(2)]
public ProtoItem BaseItem { get; set; }
}
[ProtoContract]
public class Wrapper
{
[ProtoMember(1, DataFormat = DataFormat.Group)]
public ProtoItem Item { get;set; }
public static implicit operator ProtoItem(Wrapper value)
{
return value == null ? null : value.Item;
}
public static implicit operator Wrapper(ProtoItem value)
{
return value == null ? null : new Wrapper { Item = value };
}
}
static class Program
{
static void Main()
{
var itemParent = new ProtoItem { Value = 1 };
var item2 = new ProtoItem { Value = 2, BaseItem = itemParent };
var item3 = new ProtoItem { Value = 3, BaseItem = itemParent };
var parentListToWrite = new List<Wrapper> { itemParent, item2, item3 };
const string file = "protofile.txt";
try
{ File.Delete(file); }
catch
{ };
using (var fs = File.OpenWrite(file))
{
Serializer.Serialize(fs,
parentListToWrite);
}
List<Wrapper> readList;
using (var fs = File.OpenRead(file))
{
readList = Serializer.Deserialize<List<Wrapper>>(fs);
}
if (readList[0].Item == readList[2].Item.BaseItem)
{
//how to make it equal?
System.Console.WriteLine("eq");
}
if (readList[0].Item == readList[1].Item.BaseItem)
{
//how to make it equal?
System.Console.WriteLine("eq");
}
}
}

How can I upload image and post some datas to MVC4 wep api method?

I have tried for days but I couldn't reach any successful result. I need to post images with their information (s.t. created user name).
This is my method;
[HttpPost]
public Task<HttpResponseMessage> PostFile(string createdByName)
{
HttpRequestMessage request = this.Request;
if (!request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = System.Configuration.ConfigurationSettings.AppSettings["TempUploadDir"];
var provider = new MultipartFormDataStreamProvider(root);
var task = request.Content.ReadAsMultipartAsync(provider).
ContinueWith<HttpResponseMessage>(o =>
{
AddImages(provider.BodyPartFileNames);
string file1 = provider.BodyPartFileNames.First().Value;
// this is the file name on the server where the file was saved
return new HttpResponseMessage()
{
Content = new StringContent("File uploaded.")
};
}
);
return task;
}
And this my TypeFormatterClass which is added global.asax
public class MultiFormDataMediaTypeFormatter : FormUrlEncodedMediaTypeFormatter
{
public MultiFormDataMediaTypeFormatter()
: base()
{
this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("multipart/form-data"));
}
protected override bool CanReadType(Type type)
{
return true;
}
protected override bool CanWriteType(Type type)
{
return false;
}
protected override Task<object> OnReadFromStreamAsync(Type type, Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext)
{
var contents = formatterContext.Request.Content.ReadAsMultipartAsync().Result;
return Task.Factory.StartNew<object>(() =>
{
return new MultiFormKeyValueModel(contents);
});
}
class MultiFormKeyValueModel : IKeyValueModel
{
IEnumerable<HttpContent> _contents;
public MultiFormKeyValueModel(IEnumerable<HttpContent> contents)
{
_contents = contents;
}
public IEnumerable<string> Keys
{
get
{
return _contents.Cast<string>();
}
}
public bool TryGetValue(string key, out object value)
{
value = _contents.FirstDispositionNameOrDefault(key).ReadAsStringAsync().Result;
return true;
}
}
}
When I post images and "createdByName" I can reach images but I couldn't parameters. How can I do this?
Thank you.
To get your createdByName field, inside your ContinueWith :
var parts = o.Result;
HttpContent namePart = parts.FirstDispositionNameOrDefault("createdByName");
if (namePart == null)
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
string name = namePart.ReadAsStringAsync().Result;
For a more detailed example, see :
http://www.asp.net/web-api/overview/working-with-http/html-forms-and-multipart-mime#multipartmime